Getting different Date time locally and remotely - java

I am using ZonedDateTime to convert GMT timestamp to America/Phoenix timestamp,
Here is my implementation
public static ZonedDateTime convertGMTTimestampToLocalTime(Timestamp gmtTime, String timeZone) throws Exception
{
ZonedDateTime atZone =Instant
.ofEpochMilli( // Parse a count of milliseconds since 1970-01-01T00:00Z.
gmtTime.getTime()
) // Returns a `Instant` object.
.atZone(
ZoneId.of( timeZone )
); // Returns a `ZonedDateTime` object.
return atZone;
}
This gives proper result when I test in local but when I test it remotely (server with docker container) it gives wrong result.
If I do a transaction at 6-Jan-2021 8:00PM (America/Phoenix) it should give 6-Jan-2021 instead it display 7-Jan-2021. My server is in MST
What am I missing, isn't the server supposed to print the date according to the specified time zone. Any help would be appreciated. Thanks.

Avoid legacy date-time classes
Never use the terrible legacy classes Timestamp, Date, Calendar, etc. These were years ago supplanted by the modern java.time classes defined in JSR 310.
Use java.time
If handed an object of that class, immediately convert to Instant. The Instant class represents a moment as seen in in UTC, with an offset of zero hours-minutes-seconds.
Instant instant = myTimestamp.toInstant() ;
Adjust to your desired time zone.
ZoneId z = ZoneId.of( "America/Phoenix" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
Extract the date portion.
LocalDate ld = zdt.toLocalDate() ;
Generate text representing the value of that LocalDate object.
String iso8601 = ld.toString() ;
Or automatically localize.
Locale locale = Locale.US ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDate( FormatStyle.SHORT ).
String localized = ld.format( f ) ;
You said:
My server is in MST
First, servers should generally be kept to a default time zone of UTC, that is no zone, just an offset of zero hours-minutes-seconds.
Secondly, as a Java programmer, write your code without depending on the default time zone. Specify explicitly the desired time zone by passing the otherwise optional time zone argument to the various date-time methods.
Thirdly, MST is not a real time zone.

Related

How to get the Start of day and End of Day in UTC Conversation

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”.

java.time.LocalDateTime to java.sql.Date

I am trying to implement java.time to parse different date formats and return as java.sql.Date. However I am loosing time if I use java.sql.Date.valueOf(LocalDate date).
How I can achive the same way as java.sql.Date(java.util.Date date.getTime())?
Possible formats in my application are.
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ssZ");
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
DateTimeFormatter datetimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
DateTimeFormatter datetimeFormatterMil = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
import java.sql.Date;
public Date oslcStringToDate(String str) throws ParseException
{
//remove colon in time zone
Date date = null;
if (!str.equalsIgnoreCase(NULL)) {
int colonPos = str.length() - 3;
str = str != null && str.length() > 3 && str.charAt(colonPos) == ':' ?
str.substring(0, colonPos) + str.substring(colonPos + 1)
: str.endsWith("Z") ?
str.substring(0, str.length() - 1) + "+0000"
: str;
date = str.indexOf("T") > 0 ?
str.indexOf(".") > 0 ?
java.sql.Date.valueOf(LocalDateTime.parse(str, datetimeFormatterMil).toLocalDate())
: java.sql.Date.valueOf(LocalDateTime.parse(str, datetimeFormatter).toLocalDate())
: java.sql.Date.valueOf(LocalDateTime.parse(str, dateFormatter).toLocalDate());
}
return date;
}
Do not mix legacy and modern classes
if I use java.sql.Date.valueOf(LocalDate date)
Never mix the terrible legacy classes with their replacement, the modern java.time classes defined in JSR 310.
When handed an object of a legacy class, immediately convert. You can convert to and fro by way of to…/from…/valueOf methods found on the old classes.
LocalDate ld = myJavaSqlDate.toLocalDate() ;
And the other direction.
java.sql.Date d = Date.valueOf( myLocalDate ) ;
Avoid legacy classes
With JDBC 4.2 and later, support for the java.time classes is required in your JDBC driver.
So use only the java.time classes. No need to ever use either Date, nor Calendar, SimpleDateFormat, Timestamp, etc.
Date-only values
The LocalDate class represents a date-only, without a time-of-day, without a time zone or offset-from-UTC. So a LocalDate is a year, month, and day — nothing more.
The java.sql.Date class pretends to represent a date-only value. But due to a tragically poor design decision, the class inherits from java.util.Date which does have a time-of-day. And even more confusing, the java.util.Date class is supposed to represent a moment as seen in UTC, but nevertheless contains a time zone used when generating text. These legacy classes are a master class in how to not do OOP.
You said:
However I am loosing time if I use java.sql.Date.valueOf(LocalDate date).
If you mean the resulting java.sql.Date has no time-of-day, yes, of course, that is a feature, not a bug. As mentioned above, objects of this class actually do have a time-of-day because of inheritance, but the class pretends to have a date-only (year-month-day).
You said:
How I can achive the same way as java.sql.Date(java.util.Date date.getTime())?
I cannot understand your goal here. So, after again advising against ever using these awful legacy classes, I will layout some of the possible types for use with SQL.
standard SQL
java.time ☑️
legacy ❌
DATE
LocalDate
java.sql.Date
TIME
LocalTime
java.sql.Time
TIMESTAMP WITHOUT TIME ZONE
LocalDateTIME
no support
TIMESTAMP WITH TIME ZONE
OffsetDateTime
java.sql.Timestamp
ISO 8601
Your Question is not clear, but apparently you are trying to parse text in the format of "yyyy-MM-dd'T'HH:mm:ss.SSSZ".
This format happens to comply with the ISO 8601 standard. The java.time classes use the standard formats by default when parsing/generating text. So no need to specify a formatting pattern.
Instant instant = Instant.parse( "2022-01-23T12:34:56.789Z" ) ;
To generate such text:
String output = instant.toString() ;
To record to a database, convert to the class mapped in JDBC to the standard SQL type of TIMESTAMP WITH TIME ZONE.
That SQL name is a misnomer, as the SQL standard was written with mere offset-from-UTC in mind, not real time zones. An offset is merely a number of hours-minutes-seconds ahead or behind the temporal prime meridian of UTC. A time zone, in contrast, is a named history of the past, present, and future changes to the offset used by the people of a particular region as decided by their politicians.
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
myPreparedStatement.setObject( … , odt ) ;
Retrieval.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Note that LocalDateTime is exactly the wrong class to be using in this context. The LocalDateTime class purposely lacks the context of an offset or zone. With only a date and a time-of-day, a LocalDateTime object is inherently ambiguous with regard to the timeline.
If you want to store only the date portion of your ISO 8601 string, you will need to think about time zones. For any given moment, the date varies around the globe by time zone. A moment can be “tomorrow” in Tokyo Japan while simultaneously “yesterday” in Toledo Ohio US.
Call toLocalDate to extract the date portion of an OffsetDateTime or ZonedDateTime object.
LocalDate dateInTokyo = instant.atZone( ZoneId.of( "Asia/Tokyo" ) ).toLocalDate() ;
LocalDate dateInUtc = instant.atOffset ZoneOffset.UTC ).toLocalDate() ;
LocalDate dateInToledo = instant.atZone( ZoneId.of( "America/New_York" ) ).toLocalDate() ; // Time zone name for Toledo Ohio US is `America/New_York`.
Write to a database column of a type akin to the SQL standard type DATE.
myPreparedStatement.setObject( … , dateInTokyo ) ;
Retrieval.
LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;
All of these issues have been covered many many times already in Stack Overflow. Search to learn more.

Converting string to date 2021-12-10T00:00:00 in java

I'm tring to convert this date string "2021-12-10T00:00:00" into a Date but when i deserialize it i got this.
Thu Dec 09 19:00:00 COT 2021.
it seems I'm losing one day.
Can anyone help me?
"startDate": "2021-12-10T00:00:00", and the result is this
2021-12-09T19:00:00.000-0500
tl;dr
java.util.Date.from(
LocalDateTime
.parse( "2021-12-10T00:00:00" )
.atZone(
ZoneId.of( "America/Bogota" )
)
.toInstant()
)
Details
I am guessing that you are using the terrible legacy date-time classes such as Date and Calendar. Don’t. Use only java.time class.
Your input string complies with the ISO 8601 standard for date-time formats. The java.time classes use these standard formats by default when parsing/generating strings. So no need to specify a formatting pattern.
LocalDateTime ldt = LocalDateTime.parse( "2021-12-10T00:00:00" ) ;
You said:
I'm tring to convert this date string "2021-12-10T00:00:00" into a Date
That does not make sense.
I assume by “Date”, you meant a java.until.Date. That legacy class represents a moment, a point on the timeline as seen in UTC, that is, with an offset from UTC of zero hours-minutes-seconds.
But your input lacks an indicator of time zone or offset. For example, if that string was meant to represent a moment as seen in UTC, it should have had a Z appended.
I am guessing that you assume the input was meant to represent a moment as seen in Colombia.
ZoneId z = ZoneId.of( "America/Bogota" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;
Now we have determined a moment as seen through the wall-clock time used by the people of Colombia.
Generally best to avoid java.util.Date class. But if you must, to interoperate with legacy code not yet updated to java.time, you can convert.
java.util.Date d = Date.from( zdt.toInstant() ) ;
Your start date is 2021-12-10 00:00:00 GMT+0 and your result is 2021-12-09 19:00:00 GMT-5. These times are the same. You can pass a Locale to your SimpleDataFormat constructor to be able to configure the used time zone.

Java - convert timestamp to Date and back to timestamp changes the date

I'm creating a string out from current time and I wanted to convert it to timestamp again, but the thing is, that it's subtracts 2 hours while converting.
This is the steps I'm doing -
DateTimeFormatterBuilder dateTimeFormatterBuilder = new DateTimeFormatterBuilder().append(DateTimeFormatter.ofPattern("uuuu-MM-dd")).appendLiteral(" ")
.append(DateTimeFormatter.ofPattern("HH:mm:ss")).parseLenient();
long ts = Clock.systemUTC().millis();
System.out.println(ts);
Instant instant = Instant.ofEpochMilli(ts);
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant, ZoneOffset.UTC);
String str = zonedDateTime.format(dateTimeFormatterBuilder.toFormatter());
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
long timestamp = simpleDateFormat.parse(str).getTime();
System.out.println(timestamp);
} catch (ParseException e) {
e.printStackTrace();
}
output -
1639065502667
1639058302000
(2021-12-09 15:58:22
2021-12-09 13:58:22)
why is the diff of the 2 hours?
how can I parse it so that the outputs will be equal?
tl;dr
Trying to understand Date, Calendar, and SimpleDateFormat is a huge waste of time. Use only their replacements, the java.time classes.
LocalDateTime // Represent a date with time-of-day, but lacking the context of a time zone or offset-from-UTC. So *not* a moment, *not* a point on the timeline.
.parse( // Parse your text string input into a date-time object.
"2021-12-09 15:58:22" // Your input of date with time-of-day but no offset/zone.
.replace( " " , "T" ) // Replace SPACE with a `T` to comply with standard ISO 8601 format.
) // Returns a `LocalDateTime` object.
.atZone( // Place that date-with-time into the context a particular time zone.
ZoneId.of( "America/Montreal" ) // Specify a time zone by its `Continent/Region` name.
) // Returns a `ZonedDateTime` object, a date with time-of-day as seen through the wall-clock time used by the people of a particular region. This *does* represent a moment, *is* a specific point on the timeline.
.toInstant() // Adjust from time zone to UTC (an offset of zero hours-minutes-seconds). This represents the very same moment as the `ZonedDateTime` object above, but as seen through a different wall-clock time.
.toEpochMilli() // Get a count of milliseconds from first moment of 1970 in UTC (1970-01-01T00:00Z) to the moment of our `Instant` object (& `ZonedDateTime` object).
See this code run live at IdeOne.com. There you can click fork to make a copy, alter, and run.
1639083502000
Avoid legacy date-time classes
Regarding your specific question about a two hour difference, the obvious cause would be a time zone difference.
Parsing incomplete information
Your parsing, SimpleDateFormat("yyyy-MM-dd HH:mm:ss") is something of a wild card. The result will be a java.util.Date object, which represents a moment, a date with time-of-day as seen with an offset of zero. But your input lacks an indicator of offset or zone. As commented by Sotirios Delimanolis, you are parsing with partial input, with incomplete information.
So some default zone/offset will be applied. I do not know what zone or offset in particular, because I do not care. That terrible class is tragically flawed, and should be avoided.
Also, yet another problem with the Date class is that its toString method has the anti-feature of applying the JVM’s current default time zone to adjust away from the UTC value represented by that class. Very confusing, as this creates the illusion of that zone being a part of Date object but it is not. As I said, a terrible class, tragically flawed.
Use only java.time classes instead.
java.time
Understand that a date with time-of-day is inherently ambiguous, is not a moment.
If you are tracking 4 PM on the 9th, we do not know if that means 4 PM in Tokyo Japan, 4 PM in Toulouse France, or 4 PM in Toledo Ohio US — three very different moments that happen several hours apart.
LocalDateTime ldt = LocalDateTime.parse( "2021-12-09 16:00:00" ) ;
To track a moment, a point on the timeline, you must place ne date-with-time in the context of an offset from UTC or of a time zone.
An offset is merely a number of hours-minutes-seconds ahead or behind the baseline of modern timekeeping, the prime meridian at Royal Observatory, Greenwich.
A time zone is much more. A time zone is a named history of the past, present, and future changes to the offset used by the people of a particular region. Each zone has a name in format of Continent/Region such as Europe/Berlin or Asia/Tokyo.
To track moments as seen in UTC, with an offset of zero, use Instant.
Instant instant = Instant.now() ;
To see that same moment through the wall-clock time used by people in a region, apply a ZoneId to get a ZonedDateTime.
ZoneId z = ZoneId.of( "America/Edmonton" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
As for your use of SimpleDateFormat, Date, and Calendar, don’t. Avoid these legacy date-time classes. Hey were designed by people who did not understand date-time handling. They were supplanted years ago by the modern java.time classes defined in JSR 310. Sun, Oracle, and the JCP community all gave up on those classes. I suggest you do the same.
In your code:
long ts = Clock.systemUTC().millis();
Instant instant = Instant.ofEpochMilli(ts);
That is the same as doing this:
Instant.now().truncatedTo( ChronoUnit.MILLISECONDS )
In your code:
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant, ZoneOffset.UTC);
(A) When working with mere offsets rather than time zones, use OffsetDateTime class. The ZonedDateTime class is for working with time zones.
(B) A briefer way to adjust from Instant to a zoned moment was shown above:
myInstant.atZone( z )
The answer was only setting the timezone to UTC -
DateTimeFormatterBuilder dateTimeFormatterBuilder = new DateTimeFormatterBuilder().append(DateTimeFormatter.ofPattern("uuuu-MM-dd")).appendLiteral(" ")
.append(DateTimeFormatter.ofPattern("HH:mm:ss")).parseLenient();
long ts = Clock.systemUTC().millis();
System.out.println(ts);
Instant instant = Instant.ofEpochMilli(ts);
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant, ZoneOffset.UTC);
String str = zonedDateTime.format(dateTimeFormatterBuilder.toFormatter());
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
*******
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
*******
long timestamp = simpleDateFormat.parse(str).getTime();
System.out.println(timestamp);
} catch (ParseException e) {
e.printStackTrace();
}
The dateTimeFomatter builder uses format without milliseconds and without timezone.
That's why the str value contain no information about them.
Then simpleDateFormat.parse(str) uses timezone of JVM which is UTC+02:00 in this case.
Trace what is going on:
Instant instant = Instant.now();
// => 2021-12-09 15:58:22.798 +00:00
String str = zonedDateTime.format(dateTimeFormatterBuilder.toFormatter());
// => "2021-12-09 15:58:22"
simpleDateFormat.parse(str);
// => 2021-12-09 15:58:22.000 +02:00
You just need to fix the pattern (add millis .SSS and timezone XXX parts) to make the results consistent as expected:
DateTimeFormatter.ofPattern("HH:mm:ss.SSSXXX")
// and something similar for SimpleDateFormat if needed
Parsing Instant from a custom formatted string.
This example shows how to parse Instant from serialized time assuming that there is a fixed timezone for all cases.
var serializedDateTime = "2020-01-01 10:20:30";
var zoneId = ZoneOffset.UTC; // may be any other zone
var format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
var instant = LocalDateTime
.parse(serializedDateTime, format)
// LocalDateTime is unzoned, just representation of (date + time) numbers in a single object
.atZone(zoneId)
// apply a zone to get ZonedDateTime (point in space-time on Earth)
.toInstant();
// convert to Instant (the same point adjusted to UTC+00:00)
Let me guess, your timezone is UTC+2?
simpleDateFormat.parse(str) assume that your date in current system timezone, but it is in UTC.

Set XMLGregorianCalendar value from a Calendar date in Java

what is the best way to set a XMLGregorianCalendar value from a Calendar date?
posting.setXMLGregorianCalendar(message.getCreateDate());
here my class:
Message.java
private Calendar createDate;
public Calendar getCreateDate() {
return createDate;
}
You can try out this:
Calendar createDate = Calendar.getInstance();
Date cDate = createDate.getTime();
GregorianCalendar c = new GregorianCalendar();
c.setTime(cDate);
XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
tl;dr
DatatypeFactory.newInstance().newXMLGregorianCalendar(
GregorianCalendar.from(
ZonedDateTime.now(
ZoneId.of( "Pacific/Auckland" )
)
)
)
A moment requires a time zone
The XMLGregorianCalendar, GregorianCalendar, and Calendar classes all represent a moment, that is, a date, a time-of-day, and an assigned time zone. Stay aware of the issue of time zone. If you fail to address zone explicitly, the JVM’s current default time zone will be assigned implicitly.
Specify a proper time zone name in the format of Continent/Region, such as America/Edmonton, Africa/Tunis, or Europe/Moscow. 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( "America/Montreal" ) ;
If you want to use the JVM’s current default time zone, ask for it and pass as an argument. If omitted, the code becomes ambiguous to read in that we do not know for certain if you intended to use the default or if you, like so many programmers, were unaware of the issue.
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
java.time
These …Calendar classes are also terrible. Sun, Oracle, and the JCP community gave up on them years ago with the adoption of JSR 310… and so should you. Use only the java.time classes for your business logic.
ZoneId z = ZoneId.of( "Africa/Casablanca" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ; // Capture the current moment as seen through the wall-clock time used by the people of a particular region (a time zone).
Convert
If interacting with old code not yet updated to java.time, convert between legacy classes and modern classes. Look to new methods added to the old classes.
A ZonedDateTime object can be converted to a GregorianCalendar object (a subclass of Calendar) by calling GregorianCalendar.from( ZonedDateTime ).
GregorianCalendar gregCal = GregorianCalendar.from( zdt ) ;
A GregorianCalendar can be converted to a XMLGregorianCalendar, but we have to go to one extra step. The XMLGregorianCalendar class itself lacks a converter method from GregorianCalendar. A helper class can get the job done, DatatypeFactory, as shown in this Answer by Stephen Colebourne, “JodaStephen”, the inventor of java.time.
XMLGregorianCalendar xmlGregCal = DatatypeFactory.newInstance().newXMLGregorianCalendar( gregCal );
Not that I recommend it, but you can combine this into a one-liner as seen in the tl;dr section up top.

Categories

Resources