Domanda

Trying to create an epoch value, in Java, where returned value is between now and 14 days ago.
I'm using java.util.Random.nextInt(value) and passing in 1209600, basically 14 days.
But the returned value is never older then today, how come?

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 sample outputs:

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
È stato utile?

Soluzione 2

You are supposed to use milliseconds, and in the line

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

you are just getting "seconds". To solve this, multiply by 1000 so you get a value that represents milliseconds:

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

Sample Outputs:

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

Altri suggerimenti

java.time

The legacy date-time API (java.util date-time types and their formatting type, SimpleDateFormat etc.) is outdated and error-prone. It is recommended to stop using it completely and switch to java.time, the modern date-time API*.

Moreover, avoid performing calculations yourself if there is an OOTB (Out-Of-The-Box) API available for it e.g. TimeUnit#convert. Given below is a java.time API based solution with a precision of nanosecond:

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);
    }
}

Output of a sample run:

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]

Learn more about java.time, the modern date-time API* from Trail: Date Time.

Note: I've updated the answer to incorporate the following good suggestion from Ole V.V.:

Thank you for showing the modern way. While the TimeUnit enum certainly has good uses, we don’t need it here. I’d prefer the simpler instantNow.minus(14, ChronoUnit.DAYS) and then instant14DaysAgo.plusNanos(ThreadLocalRandom.current().nextLong(ChronoUnit.NANOS.between(instant14DaysAgo, instantNow))).


* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Confusion about milliseconds and seconds was the reason here as recognized before but I would suggest a slightly modified solution to achieve two goals:

  1. output only in full seconds (see the wished format pattern)
  2. more stability regarding integer overflow (imagine, OP wants to change 14 to maybe 100)

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top