I need to create a class that implements JsonbDeserializer < ZonedDateTime > , but, the data (string) to be parsed could be in this format "2021-05-31" or this format "2021-05-31T09:30:57.544797".
How could I deal with this scenario?
Neither of your pieces of example data are suitable for a ZonedDateTime object.
Date without time, and without zone
"2021-05-31" represents a date-only value. Use LocalDate class.
LocalDate ld = LocalDate.parse( "2021-05-31" ) ;
If you want to make a ZonedDateTime of that, you’ll to assign a time-of-day and a time zone.
Perhaps you’d want the first moment of the day as the time. If so, do not assume that first moment is at 00:00:00. Some dates in some zones start at a different moment such as 01:00:00. Let java.time determine the first moment.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = ld.atStartOfDay( z ) ;
Date and time without zone
"2021-05-31T09:30:57.544797" represents a date with a time of day, but lacks an indicator of time zone or offset from UTC. So parse as a LocalDateTime.
LocalDateTime ldt = LocalDateTime.parse( "2021-05-31T09:30:57.544797" ) ;
If you want to make a ZonedDateTime of that, assign a time zone. Be aware the time of day may change to adjust for gaps caused by anomalies such as Daylight Saving Time (DST).
ZoneId z = ZoneId.of( "Asia/Japan" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;
Related
Hello I am trying to Start of Day
Like in India TimeZone
Start of Day is: 2022-11-20 00:00:00 (local time in India)
In UTC: 2022-11-20 05:30:00 PM
tl;dr
LocalDate // Represent a date-only value, without time-of-day, without time zone or offset.
.now( ZoneId.of( "Asia/Kolkata" ) ) // Capture the current date as seen in a particular time zone. For any given moment, the date varies around the globe by time zone.
.atStartOfDay( ZoneId.of( "Asia/Kolkata" ) ) // Determine the first moment of the day. May or may not be 00:00. Returns a `ZonedDateTime` object.
.toInstant() // Adjust to an offset from UTC of zero hours-minutes-seconds. Returns an `Instant` object.
.toString() // Generate text in standard ISO 8601 format. Returns a `String` object, containing formatted text.
2022-11-19T18:30:00Z
Details
Capture the current date.
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
LocalDate today = LocalDate.now( z ) ;
Get the first moment of that day. Do not assume the day starts at 00:00. Some days on some dates in some time zones start at a different time of day such as 01:00. Let java.time determine the first moment.
ZonedDateTime zdt = today.atStartOfDay( z ) ;
To view that same moment through the wall-clock time of UTC (an offset from UTC of zero hours-minutes-seconds), extract an Instant. An Instant represents a moment, a specific point on the timeline, as seen in UTC.
Instant instant = zdt.toInstant() ;
See that code run at Ideone.com.
today.toString(): 2022-11-20
zdt.toString(): 2022-11-20T00:00+05:30[Asia/Kolkata]
instant.toString(): 2022-11-19T18:30:00Z
To generate text in various formats, use OffsetDateTime rather than Instant. The Instant class is a basic building-block class in java.time. The OffsetDateTime class is more flexible, including features for generating text in formats other than standard ISO 8601 format.
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
To learn more about generating text, search Stack Overflow for existing Questions and Answers about DateTimeFormatter class.
Java 8+ comes with an implementation of java.time. Ditto for Android 26+. For earlier Android, the latest tooling provides most of the java.time functionality via “API desugaring”.
Hey I have Iso Format date. I want to compare with current date. If date is equal to current date, I need the time of given Iso date and otherwise i need date.
val date = "2021-10-01T18:39:10.0492422+01:00"
How to compare today’s date with this value. If date is match i need time in HH:MM otherwise dd MMM YYYY format.
Important thing my minSdkVersion 21
tl;dr
Java syntax, as I don’t know Kotlin:
LocalDate
.now( ZoneId.of( "America/Edmonton" ) )
.isEqual(
OffsetDateTime
.parse( "2021-10-01T18:39:10.0492422+01:00" )
.atZoneSameInstant( ZoneId.of( "America/Edmonton" ) )
.toLocalDate()
)
As for generating text from java.time objects in specific formats using DateTimeFormatter and DateTimeFormatterBuilder classes, that has been covered many many times already. Search to learn more.
Details
The latest Android tooling brings much of the java.time functionality built into Android 26+ to earlier Android via “API de-sugaring”.
In Java syntax…
Parse your input as a OffsetDateTime.
OffsetDateTime odt = OffsetDateTime.parse( "2021-10-01T18:39:10.0492422+01:00" ) ;
Adjust to the time zone by which you perceive “today’s date”.
ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
Get today’s date as seen in your target time zone, a LocalDate.
LocalDate today = LocalDate.now( z ) ;
Compare to the date of our input as seen in the same time zone.
boolean sameDate = today.isEqual( zdt.toLocalDate() ) ;
As seen above, you must provide a time zone. For any given moment, the date varies around the globe by time zone. Right now is “tomorrow” in Tokyo Japan while simultaneously “yesterday” in Toledo Ohio US. So to ask “what is the date today?”, you must also specify where, that is, by what time zone do you want to perceive the current date.
I am trying to parse an input string to local date time.
Below is my piece of code
ZonedDateTime z = ZonedDateTime.parse("2019-11-26T19:30:00Z", MY_DATE_TIME_FORMATTER);
where
MY_DATE_TIME_FORMATTER= new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(ISO_LOCAL_DATE)
.appendLiteral('T')
.append(ISO_LOCAL_TIME)
.appendLiteral('Z')
.appendOffset("+HH:mm", "+0000")
.toFormatter();
I get the following exception
java.time.format.DateTimeParseException: Text '2019-11-26T19:30:00Z' could not be parsed at index 19
Can you please advise on what I am doing wrong here?
Instant.parse
No formatting pattern needed.
Instant.parse( "2019-11-26T19:30:00Z" )
Your input format complies with ISO 8601 standard. That particular format has a Z on the end. That letter means UTC (an offset of zero hours-minutes-seconds), and is pronounced “Zulu”.
The Instant class in java.time represents a moment in UTC, always UTC.
Using ZonedDateTime class for that input is not the most appropriate. We have:
Instant for values that are always in UTC.
OffsetDateTime for moments where only an offset-from-UTC is known but not a time zone. Use this class for UTC values too when you need more flexibility such as generating strings in various formats. `instant.atOffset(
ZonedDateTime for values in a time zone. A time zone is a history of past, present, and future changes to the offset used by the people of a particular region.
To view that same moment adjusted to the offset used by the people of a particular region (a time zone), apply a ZoneId to get a ZonedDateTime object.
Instant instant = Instant.parse( "2019-11-26T19:30:00Z" ) ; // Default format for parsing a moment in UTC.
ZoneId z = ZoneId.of( "America/Edmonton" ) ; // A time zone is a history of past, present, and future changes to the offset used by the people of a particular region.
ZonedDateTime zdt = instant.atZone( z ) ; // Same moment, same point on the timeline, different wall-clock time.
See this code run live at IdeOne.com.
instant.toString(): 2019-11-26T19:30:00Z
zdt.toString(): 2019-11-26T12:30-07:00[America/Edmonton]
Add
.appendZoneOrOffsetId()
instead of these two lines:
.appendLiteral('Z')
.appendOffset("+HH:mm", "+0000")
The whole builder example:
MY_DATE_TIME_FORMATTER= new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(ISO_LOCAL_DATE)
.appendLiteral('T')
.append(ISO_LOCAL_TIME)
.appendZoneOrOffsetId()
.toFormatter();
P.S. In your specific case I'd rather use the standard ISO formatter (as Hristo mentioned):
ZonedDateTime z = ZonedDateTime.parse("2019-11-26T19:30:00Z", DateTimeFormatter.ISO_ZONED_DATE_TIME);
Moreover, the ZonedDateTime::parse method will work even without the explicit formatter. Since it's used by default:
ZonedDateTime z = ZonedDateTime.parse("2019-11-26T19:30:00Z");
Use the built in ISO zoned time formatter
ZonedDateTime.parse("2019-11-26T19:30:00Z", DateTimeFormatter.ISO_ZONED_DATE_TIME);
I Have UTC String with a format (HH: mm: ss) and I need to convert the String value into device Time in the same format (HH: mm: ss) and also adding Day saving time if available I Have Tried to convert the UTC String to device time by this code but I am getting a 1 hour delay due to (day saving time).
String utcTimeString = "12:15:00"
SimpleDateFormat formatter = new SimpleDateFormat("HH: mm: ss");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
Date value = formatter.parse(utcTimeString);
SimpleDateFormat dateFormatter = new SimpleDateFormat("HH: mm: ss");
dateFormatter.setTimeZone(TimeZone.getDefault());
utcDateString = dateFormatter.format(value);
My Time Zone is GMT-4
Expected Output: 08:15:00;
Given Output: 07:15:00;
The Answer by deHaar is generally correct, and wisely makes use of the modern java.time classes. However, I would use a slightly different approach.
tl;dr
OffsetDateTime.of( // Represent a moment as a date, a time-of-day, and an offset-from-UTC.
LocalDate.now( ZoneOffset.UTC ) , // Current date as seen right now in UTC. Beware: For any given moment, the date varies around the globe by zone.
LocalTime.parse( "12:15:00" ) , // Your specified time-of-day.
ZoneOffset.UTC // An offset of zero hours-minutes-seconds, for UTC itself.
) // Returns an `OffsetDateTime` object.
.atZoneSameInstant( // Adjust from UTC to a time zone. Same moment, different wall-clock-time.
ZoneId.of( "America/Port_of_Spain" ) ; // One of the many time zones that are behind UTC by four hours on that date.
) // Returns a `ZonedDateTime` object.
.toLocalTime() // Extract the time-of-day only, leaving behind the date and the zone.
Time zone
My Time Zone is GMT-4
Nope. That is not a time zone.
The value GMT-4 represents merely an offset-from-UTC. A number of hours-minutes-seconds ahead or behind the UTC baseline.
A time zone is much more. A time zone has a name, and represents the history of past, present, and future changes the offset used by the people of a particular region. Therefore, a time zone is always preferable to a mere offset.
Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "Africa/Casablanca" ) ;
If your time zone is currently four hours behind UTC, you must be in a time zone such as America/Aruba, America/Puerto_Rico, America/Manaus, America/Martinique, etc.
ZoneId z = ZoneId.of( "America/Martinique" ) ;
UTC
I Have UTC String with a format (HH: mm: ss)
Nope.
A value such as "12:15:00" cannot be said to be a value in UTC. Without a date, that value has no real meaning. A moment consists of three parts:
a date,
a time-of-day, and
an offset/zone.
Saying "noon in UTC" only gives us 2 of the 3 parts. The date is missing.
Today… what a concept
Perhaps you want to apply that time-of-day to the current date as seen in UTC.
LocalDate todayUTC = LocalDate.now( ZoneOffset.UTC ) ;
Just keep in mind that for any given moment the date varies around the globe by zone. At this very moment, the date is “tomorrow“ in Tokyo Japan while still being “yesterday” in Toledo Ohio US.
OffsetDateTime
Combine all three into a OffsetDateTime object: date, time-of-day, and offset/zone.
LocalTime localTime = LocalTime.parse( "12:15:00" ) ;
OffsetDateTime odt = OffsetDateTime.of( todayUTC , localTime, ZoneOffset.UTC ) ;
ZonedDateTime
Adjust from UTC to your particular time zone. Same moment, same simultaneous point on the timeline, different wall-clock time. Apply a ZoneId to get a ZonedDateTime object. The time zone nows about if and when Daylight Saving Time (DST) applies for this particular zone, and adjusts accordingly.
ZoneId z = ZoneId.of( "America/Martinique" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
Wrong approach
You should not be adding/subtracting some number of hours from a LocalTime. On some dates in some zones, a particular time-of-day may not exist. For example, for Daylight Saving Time, on the day of "Spring-ahead", in the United States, a time-of-day of 02:15:00 does not exist, as the clock jumps ahead from 02:00:00 to 03:00:00.
The correct approach using the ZonedDateTime class will automatically adjust accordingly.
You can use java.time, the modern date time API, and parse the time String to a moment in time, that is an Instant.
Then use ZonedDateTime objects to apply a certain time zone, which may be done in different ways, I show you one of them here:
public static void main(String[] args) {
// the source is just a time, but to correctly convert it, you need a date
String utcTime = "12:15:00";
// take today's date
LocalDate today = LocalDate.now();
// create a parseable date time String
String parseableDateTime = today.format(DateTimeFormatter.ISO_DATE) + "T" + utcTime + "Z";
// then create an Instant parsing the date time String
Instant instant = Instant.parse(parseableDateTime);
// get the ZoneId of UTC in order to have the time in UTC
ZoneId utc = ZoneId.of("UTC");
// do the same with your ZoneOffset of -4 Hours
ZoneId gmtMinusFour = ZoneId.ofOffset("GMT", ZoneOffset.ofHours(-4));
// create a UTC ZonedDateTime of the instant and the UTC ZoneID
ZonedDateTime utcZdt = ZonedDateTime.ofInstant(instant, utc);
// then use that ZonedDateTime to convert it to a time with your ZoneId
ZonedDateTime gmtMinusFourZdt = utcZdt.withZoneSameInstant(gmtMinusFour);
// finally print both ZonedDateTimes in order to compare them
System.out.println("UTC time is:\t\t"
+ utcZdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
System.out.println("GMT-4 time is:\t\t"
+ gmtMinusFourZdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
// then just get the time part of the converted ZonedDateTime
LocalTime localTime = gmtMinusFourZdt.toLocalTime();
// and print it
System.out.println("Converted time is:\t"
+ localTime.format(DateTimeFormatter.ISO_TIME));
}
Output:
UTC time is: 2019-09-24T12:15:00Z[UTC]
GMT-4 time is: 2019-09-24T08:15:00-04:00[GMT-04:00]
Converted time is: 08:15:00
There may be better solutions, but I hope this helps anyway…
This question already has answers here:
Change date format in a Java string
(22 answers)
Closed 4 years ago.
I want to display complete date in mySQL format but don't want to see the Time along with it.
Wanted to increment or decrement the date to perform actions
tl;dr
myResultSet.getObject( … , Instant.class )
.atZone( ZoneId.of( "Pacific/Auckland" ) )
.toLocalDate()
.toString()
Details
For a column of type akin to the SQL-standard TIMESTAMP WITH TIME ZONE, retrieve as a Instant.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
An Instant is always in UTC. Adjust into the time zone by which you want to perceive the date according to the wall-clock time used by the people of a certain region. For any given moment, the date varies around the world by zone. It might be “tomorrow” in Asia/Kolkata India while still “yesterday” in America/Montreal Canada.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
Extract the date-only, as that is what you want to focus on.
LocalDate ld = zdt.toLocalDate() ;
Use the various plus/minus methods to add or subtract days, weeks, months, years, or a combination of those (Period).
LocalDate dayAfter = ld.plusDays( 1 ) ;
Or…
Period p = Period.parse( "P3M7D" ) ;
LocalDate later = ld.plus( p ) ;
For a database type akin to SQL-standard TIMESTAMP WITHOUT TIME ZONE, retrieve as a LocalDateTime. Skip the part above with time zone. Go directly to extracting the LocalDate. Proceed with your addition/subtraction.
myResultSet.getObject( … , LocalDateTime.class )
.toLocalDate()
.plusDays( 1 )
.toString()
To generate a String representing the date value in standard ISO 8601 format, call LocalDate::toString(). For other formats, use DateTimeFormatter. Search Stack Overflow to learn more.