创建一个从X天前到现在的随机纪元值

时间:2014-04-09 16:05:23

标签: java random epoch

尝试在Java中创建一个纪元值,其中返回值介于现在和14天之前 我使用java.util.Random.nextInt(value)并传递1209600,基本上是14天 但是返回的价值从来没有比现在更早,为什么呢?

public class Debug {

    private static final Random rng = new Random();

    public static void main(String[] args) {
        long now = System.currentTimeMillis();
        long timeSinceLastVisit = rng.nextInt(14 * 24 * 60 * 60);
        long timeOfLastVisit = now - timeSinceLastVisit;
        String date = new java.text.SimpleDateFormat("MM/dd/yyyy HH:mm:ss").format(new java.util.Date (timeOfLastVisit));

        System.out.println("1. " + timeOfLastVisit);
        System.out.println(date);
    }
}

5个样本输出:

1. 1397057814065
04/09/2014 16:36:54

1. 1397058754779
04/09/2014 16:52:34

1. 1397058553618
04/09/2014 16:49:13

1. 1397058294674
04/09/2014 16:44:54

1. 1397058408390
04/09/2014 16:46:48

3 个答案:

答案 0 :(得分:2)

java.time

旧的日期时间 API(java.util 日期时间类型及其格式类型,SimpleDateFormat 等)已经过时且容易出错。建议完全停止使用,改用java.timemodern date-time API*

此外,如果有可用的 OOTB(开箱即用)API,请避免自己执行计算,例如TimeUnit#convert。下面给出了一个基于 java.time API 的解决方案,精度为纳秒:

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

public class Main {
    public static void main(String[] args) {
        Instant instantNow = Instant.now();

        Instant instant14DaysAgo = instantNow.minus(14, ChronoUnit.DAYS);

        // A random instant from 14 days ago until a nanosecond ago
        Instant instantRandom = instant14DaysAgo.plusNanos(
                ThreadLocalRandom.current().nextLong(ChronoUnit.NANOS.between(instant14DaysAgo, instantNow)));
        System.out.println(instantRandom);

        // The corresponding Epoch milliseconds
        System.out.println(instantRandom.toEpochMilli());

        // The corresponding Epoch seconds
        System.out.println(TimeUnit.SECONDS.convert(instantRandom.toEpochMilli(), TimeUnit.MILLISECONDS));

        // The corresponding date-time in JVM's timezone
        ZonedDateTime zdtJvm = instantRandom.atZone(ZoneId.systemDefault());
        System.out.println(zdtJvm);

        // The corresponding date-time in a specific timezone
        ZonedDateTime zdtToronto = instantRandom.atZone(ZoneId.of("America/Toronto"));
        System.out.println(zdtToronto);
    }
}

示例运行的输出:

2021-05-07T01:52:12.382493303Z
1620352332382
1620352332
2021-05-07T02:52:12.382493303+01:00[Europe/London]
2021-05-06T21:52:12.382493303-04:00[America/Toronto]

modern date-time API 中详细了解 java.timeTrail: Date Time*

注意:我已经更新了答案以纳入来自 Ole V.V. 的以下好建议:

<块引用>

感谢您展示现代方式。而 TimeUnit 枚举 当然有很好的用途,我们这里不需要它。我更喜欢简单的 instantNow.minus(14, ChronoUnit.DAYS) 然后 instant14DaysAgo.plusNanos(ThreadLocalRandom.current().nextLong(ChronoUnit.NANOS.between(instant14DaysAgo, instantNow)))


* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 & 7. 如果您正在为 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project

答案 1 :(得分:1)

您应该使用毫秒,并在行

long timeSinceLastVisit = rng.nextInt(14 * 24 * 60 * 60);

你刚刚得到&#34;秒&#34;。要解决此问题,请乘以1000,以便得到一个代表毫秒的值:

long timeSinceLastVisit = rng.nextInt(14 * 24 * 60 * 60 * 1000);

示例输出:

04/01/2014 21:56:04
04/03/2014 21:44:41
04/07/2014 05:38:58
03/29/2014 22:19:29
04/02/2014 08:54:51

答案 2 :(得分:0)

关于毫秒和秒的混淆是之前认可的原因,但我建议稍微修改一下,以实现两个目标:

  1. 仅在整秒内输出(参见所需的格式模式)
  2. 关于整数溢出的更多稳定性(想象一下,OP希望将14改为100)

    long timeSinceLastVisit = rng.nextInt(14 * 24 * 60 * 60)* 1000L;