As for the issue of getting a timestamp, use the java.time classes.
Capture the current moment as seen in UTC.
Instant instant = Instant.now() ;
To get a fake time, pass a
Clock class has methods that offer variants with special behaviors, ideal for testing. Those behaviors include being stuck at a certain moment, being offset from the true time yet incrementing forward in time, and altered cadence such as incrementing only by a full minute at a time. To explicitly use the normal default
Clock.systemUTC() as discussed here.
Here we specify the moment of noon on a certain date in a certain zone. For this we want to use
ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
LocalDate ld = LocalDate.of( 2021 , Month.JANUARY , 23 ) ;
LocalTime lt = LocalTime.NOON ;
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;
Adjust to UTC. Same moment, same point on the timeline, different wall-clock time.
Instant instant = zdt.toInstant() ;
Make the fake.
Clock clock = Clock.fixed( instant , z ) ;
Use the fake.
Instant instantFake = Instant.now( clock ) ;
Asia/Tokyo is nine hours ahead of UTC at that moment. So this result makes sense. Going nine hours back from noon there is 3 AM in UTC ( 12-9 = 3 ).
ISO 8601 Basic format
String with text in standard ISO 8601 format. The
Z you see on the end means UTC and is pronounced “Zulu”.
String output = instantFake.toString() ;
The format you desire is nearly compliant with the “basic” variant allowed in ISO 8601. Two differences:
T in the middle, separating the year-month-day from the hour-minute-second.
Z on the end, indicating UTC as the offset/zone.
I suggest you adopt both of those features. The first makes your string more recognizable as a date-time rather than some arbitrary identifier. The second provides a context in which to interpret the date and the time. Without a context, the reader has no way of knowing if you meant 3 AM in Tunisia, 3 AM in Toledo Ohio US, 3 AM in UTC, or 3 AM somewhere else — all different moments, several hours apart.
DateTimeFormatter with a custom formatting pattern. To use a custom formatter, we need to convert from the basic class
Instant to the more flexible class
OffsetDateTime odt = instantFake.atOffset( ZoneOffset.UTC ) ;
Define our custom formatting pattern.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuuMMdd'T'HHmmssX" );
String output = odt.format( f );
And use that formatter to parse such strings back into
OffsetDateTime object, and extract a
Instant instantReplay = OffsetDateTime.parse( output , f ).toInstant();
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for
java.sql.* classes. Hibernate 5 & JPA 2.2 support java.time.
Where to obtain the java.time classes?