Java Date and Calendar without concept of TimeZone (Regardless of Timezone) - java

I need to record the time of different systems whose default behavior would convert the input time into the systems' timezone. While what I want is to disable the convert. So in system 1, I need to construct a Calendar whose timezone is same with the system 2. For example, system 1's default timezone is PDT, system 2's default timezone is GMT, the time needed to create calendar is 2011/08/23 4:00 in PDT, what I need is to create a calendar in system 1 like 2011/08/23 4:00 in GMT.
In other words, How to create a Calendar without the concept of Timezone

I would abandon java.util.{Date, Calendar} at this point and flee to the comfort of Joda Time, where you would create a LocalDateTime. (Joda Time is a far superior date/time API.)
If you really want to stick with Calendar, you can just use the same time zone everywhere - the simplest approach being UTC as that doesn't have any daylight saving time.
Alternatively, it's not clear that you really want a Calendar without the concept of a TimeZone - but a Calendar which uses a TimeZone other than the system default - which is easy; you just set the time zone for the calendar explicitly. Of course you need to know the time zone of the other system that way...
If you can give more details of what information you know and what you need to do with it, we may be able to help you more.

Calendar from the definition is a date in some calendar system (typically Gregorian) and in a specified TimeZone.
If you don't care about time zone (or more precisely: you want points in time regardless of time zone), simply use Date. Despite its name, it actually stores the exact moment in time, not a date in some calendar.

How about just using the long epoch time returned from System.currentTimeMillis() and friends ?

java.util.Date does not have the concept of a timezone, it is just a thin wrapper around a GMT timestamp (if used correctly). It only may seem otherwise because its toString() method and some other legacy methods of the class implicitly use the system default timezone.
Calendar is only needed for date calculations, so you should not have to use it at all. All you need is to use SimpleDateFormat with the correct timezone to convert (format/parse) between Date instances (which do not have a timezone) and String representations (which have one, possibly GMT).

Have a look at Veyder-time. It is a simple and efficient framework for time and date manipulation, and has a natural representation of these objects. Veyder-time is completely free from all complications such as TimeZones, epochs, eras, different calendar systems and such.
With Veyder-time, creating time and date objects, without any time zone, is simple. Look at these examples:
Time now = Time.factory.now();
Time time = Time.factory.parse("2011-08-01 12:49:21.123");

There can be many use cases like
- we don't need time zone
- we don't need hours
- we don't need minutes
- we don't need milli seconds
In such cases we can just clear tall such fields which are causing trouble and are not required
calendar.clear(Calendar.ZONE_OFFSET);
calendar.clear(Calendar.MILLISECOND);
calendar.clear(Calendar.HOUR);
calendar.clear(Calendar.MINUTE);
All such fields are listed here - this link might be usful
https://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html

java.time
The Answer by Jon Skeet is correct but now outdated.
As he said, the old legacy date-time classes are a mess and should be avoided. The Joda-Time project is now in maintenance mode, with the team advising migration to java.time.
LocalDateTime
The LocalDateTime class represents a date and a time-of-day with a resolution of nanoseconds. This value is unattached to the timeline, without any concept of offset-from-UTC nor time zone.
As such it does not represent an actual moment but a potential moment. When you place it in the context of an offset or time zone, then you imbue the new value (a OffsetDateTime or ZonedDateTime) with meaning as it becomes a point on the timeline.
For example, 2016-12-25T00:00:00 is when Christmas begins this year. But that stroke of midnight happens first in the Pacific such as Auckland New Zealand, which is earlier than Christmas in Kolkata India. And Christmas begins even later in Paris France, still later in Montréal Québec. That is why Santa starts in the east and works westward with his deliveries.
LocalDateTime xmas2016 = LocalDateTime.of( 2016 , Month.DECEMBER , 25 , 0 , 0 ) ;
Zoned
While your Question is not clear, I suspect what you really need is date-time values in UTC. All your various inputs in various time zones should be normalized into UTC.
Programmers should think of UTC as the One True Time. Most of your business logic, logging, data storage, and data exchange should generally be done in UTC. I suggest you keep a second clock on your desk set to UTC.
The Instant class represents a moment on the time line in UTC with a resolution of nanoseconds.
Instant instant = Instant.now();
When you need to see the wall-clock time for some offset-from-UTC, apply a ZoneOffset to get a OffsetDateTime object. To see the wall-clock time for some time zone, apply a ZoneId to get a ZonedDateTime.
ZonedDateTime xmas2016Montréal = xmas2016.atZone( ZoneId.of( "America/Montreal" ) );
Both of these offset/zoned date-time objects can get you back to an Instant with a call to toInstant.
Instant instant = xmas2016Montréal.toInstant(); // Convert to UTC.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to java.time.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP (see How to use…).
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Related

How to fetch correct date and time without server time in java with time zone as input

I have my app hosted in a London Server. I am in Minasota, USA. So the timezone is different hours.
How can I obtain the current date / time with my time zone. The tricky part is i don't want to fetch current date and time based on server date and time. Is there a way i can fetch the real current date and time based on time zone.
The below code returns information but if the server date is invalid then the response will be invalid date too. But i want the REAL current date and time.
My input will be time zone. Any help is appreciated.
Date date = new Date();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// Use Minasota's time zone to format the date in
df.setTimeZone(TimeZone.getTimeZone("America/Minasota"));
System.out.println("Date and time in Minasota: " + df.format(date));
It's important to know that the use of the three letter time-zone abbreviations is deprecated in java 8. So, don't expect them to be supported forever. Here are two equivalent examples of using the java 8 time api to achieve this:
System.out.println(Instant.now().atZone(ZoneId.of("CST",ZoneId.SHORT_IDS)));
System.out.println(Instant.now().atZone(ZoneId.of("America/Chicago")));
This question is possibly a duplicate of this
tl;dr
Is there a way i can fetch the real current date and time based on time zone.
Yes. Use modern java.time rather than terrible legacy classes.
ZonedDateTime.now( // Represent a moment as seen through the wall-clock time used by the people of a particular region (a time zone).
ZoneId.of( "America/Chicago" ) // Specify time zone by proper `Continent/Region` name, *never* 2-4 letter pseudo-zones such as “CST”.
) // Returns a `ZonedDateTime` object.
.toString() // Generate text in standard ISO 8601 format wisely extended to append the name of the time zone in square brackets.
2018-11-07T14:38:24.723394-06:00[America/Chicago]
Details
I have my app hosted in a London Server. I am in Minasota, USA.
This should be irrelevant to your app.
Server should default to UTC time zone (generally).
Client should be asked to confirm their desired/expected time zone (when critical).
Always specify explicitly your desired/expected time zone by passing optional argument rather than relying implicitly on the JVM’s current default time which can change at any moment during runtime(!).
How can I obtain the current date / time with my time zone.
Firstly, most of your business logic, storage, and exchange of date-time values should be done in UTC.
Instant instant = Instant.now() ; // Current moment in UTC.
You can see that same moment through the lens of a wall-clock time used by the people of a particular region, a time zone.
The time zone for Minnesota is America/Chicago.
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 CST or EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Chicago" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
As a shortcut, you can skip the Instant.
ZonedDateTime zdt = ZonedDateTime.now( z ) ;
But i want the REAL current date and time
➥ Here is the core concept in mastering date-and-time work: The Instant (UTC) and the ZonedDateTime (some time zone) seen above represent the very same moment. Those two objects represent the same point on the timeline. They are both the “REAL date and time”. They use two different wall-clock times to show the same moment.
If a person in Iceland were on the phone with someone in Minneapolis, and they both look up their respective clocks & calendars on the wall to speak aloud the current date and time, which one of them is correct? Both are correct, two ways to express the same simultaneous moment.
Indeed, you would do well to think of UTC as The One True Time™, with all zoned times as mere variations. Focusing on your own parochial time zone, and then translating back-and-forth, will drive you batty. Focus on UTC, adjust into a time zone only when expected by the user or necessitated by business logic.
This has all been covered many times already on Stack Overflow. So search for more info and examples. And learn to search Stack Overflow before posting.
To generate strings, either call toString for text in standard ISO 8601 format, or use DateTimeFormatter.ofLocalized… to automatically localize, or use DateTimeFormatter.ofPattern to specify a custom formatting pattern. This has been covered many many times on Stack Overflow, so search for more info.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
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.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Gregorian Calendar Wrong Hour

So, I started to test around a bit with the Java-GregorianCalendar Class and noted a weird behaviour occuring, when initializing the Object with milliseconds. What bothered me was, although I set the milliseconds to 0 the time showed 1 o'clock.
After browsing StackOverflow a bit I noticed that Java sometimes gets confused with summer and winter time. So my question is, if although the time change was already done this year and we live in winter time again, this weird behaviour comes from winter and summertime.
Here is the Code I was testing around with:
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
public class TestCalendar {
public static void main(String[] args) {
GregorianCalendar c = new GregorianCalendar();
c.setTimeInMillis(-3600000);
System.out.println(c.getTimeInMillis());
System.out.println(c.get(Calendar.HOUR));
String format = "mm:ss";
if (c.get(Calendar.HOUR_OF_DAY) > 0) format = "HH:mm:ss";
System.out.println(new SimpleDateFormat(format).format(c.getTime()));
}
}
This gave me the Output
-3600000
0
0
The best thing would be to find a solution which is independent from substracting -3600000 as if on other computers this "bug" does not exist I dont want to have 23:00:00 :)
EDIT:
After trying a bit more out and thanks to the Feedback I was able to fix my little problem by just adding this line just after initializing the Calendar:
c.setTimeZone(TimeZone.getTimeZone("GMT"));
tl;dr
Problem: You are mistakenly changing the date, not just the time-of-day. On top of that, a time zone is implicitly being applied.
Solution: Instead use the modern java.time classes.
LocalDate
.now() // Better to explicitly pass the desired/expected time zone as a `ZoneId` object.
.atStartOfDay() // Again, better to explicitly pass the desired/expected time zone as a `ZoneId` object.
Returns a LocalDateTime (BEWARE: Not a moment, not a point on the timeline).
2018-11-01T00:00
Much better to specify time zone.
LocalDate
.now(
ZoneId.of( "Pacific/Auckland" )
)
.atStartOfDay(
ZoneId.of( "Pacific/Auckland" )
)
Returns a ZonedDateTime. This is a moment, is a point on the timeline.
2018-11-02T00:00+13:00[Pacific/Auckland]
GregorianCalendar::setTimeInMillis is not setting time-of-day
Apparently you mistakenly thought the GregorianCalendar::setTimeInMillis would set the time-of-day without affecting the date. Among the many flaws in these legacy date-time classes is some very poor choices in naming classes and methods.
But, no, that method redefines the moment as a count of milliseconds since epoch reference date of 1970-01-01T00:00Z.
Add in the time zone implicitly assigned to GregorianCalendar, and you have unexpected results.
I started to test around a bit with the Java-GregorianCalendar
Don’t.
Those old date-time classes bundled with the earliest versions of Java are terrible. They were supplanted years ago by the java.time classes defined in JSR 310.
Specifically, to track a moment in UTC, use Instant.
initializing the Object with milliseconds
Don’t.
Tracking time as a count-from-epoch-reference is prone to error. There are many different epoch reference dates in use in the industry. There are different granularities in use in the industry (whole seconds, milliseconds, microseconds, nanoseconds).
So a count-from-epoch is ambiguous. Also prone to confusing and missed errors because humans cannot read the meaning of the values.
When exchanging date-time values, use strings in standard ISO 8601 format instead.
When handed a count of milliseconds from the Unix epoch of first moment of 1970 in UTC, parse as an Instant.
Instant instant = Instant.ofEpochMilli( … ) ;
java.time
The modern solution uses java.time classes instead.
Get your date.
LocalDate
The LocalDate class represents a date-only value without time-of-day and without time zone or offset-from-UTC.
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment during runtime(!), so your results may vary. Better to specify your desired/expected time zone explicitly as an argument.
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( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
If you want to use the JVM’s current default time zone, ask for it and pass as an argument. If omitted, the JVM’s current default is applied implicitly. Better to be explicit, as the default may be changed at any moment during runtime by any code in any thread of any app within the JVM.
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
Or specify a date. You may set the month by a number, with sane numbering 1-12 for January-December.
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Or, better, use the Month enum objects pre-defined, one for each month of the year. Tip: Use these Month objects throughout your codebase rather than a mere integer number to make your code more self-documenting, ensure valid values, and provide type-safety.
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
ZonedDateTime
Apparently you want the first moment of the day. By the way, do not think of this as “midnight” as that term is ambiguous.
The first moment of the day may not be 00:00. Anomalies such as Daylight Saving Time (DST) mean that the first moment on some dates in some zones may be another time such as 01:00. Let java.time determine the first moment.
Specify a time zone.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = localDate.atStartOfDay( z ) ;
If you want to see that same moment in UTC, extract a Instant.
Instant instant = zdt.toInstant() ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
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.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
Setting c.setTimeInMillis(0); sets the time to January 1, 1970 at 00:00:00 GMT (1970-01-01 00:00:00 GMT) which is called the epoch
https://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html#setTimeInMillis(long)
public void setTimeInMillis(long millis)
Sets this Calendar's current time from the given long value.
Parameters:
millis - the new time in UTC milliseconds from the epoch.
See Also:
setTime(Date), getTimeInMillis()
If you want to set the time to midnight, I think you want to do.
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);

Getting the TimeZoneIDs for a Time Zone

I am dealing with Time and Date in Java.
I am having date as : 2018-08-22T22:00:00-0500
My Time Zone offset here is -0500
How can I get the list of available Time Zone IDs?
My main objective here is to set a date to a particular Time Zone. However I do not know the time zone as it is embedded in this date format.
Update :
My question is different from Java TimeZone offset
as according to the accepted answer to that question, I need to have time zone info : "Europe/Oslo" . However I only have offset. See the accepted answer below which solves my problem.
tl;dr
eachZoneId.getRules().getOffset(
OffsetDateTime.parse(
"2018-08-22T22:00:00-0500" ,
DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ssX" )
).toInstant()
).equals( myTargetZoneOffset )
Offset versus Zone
I do not know the time zone as it is embedded in this date format.
No, your input string of 2018-08-22T22:00:00-0500 has no time zone. It has only a mere offset-from-UTC.
An offset is simply a number of hours, minutes, and seconds of displacement ahead of, or behind, UTC. Yours shows an offset five hours behind UTC. In contrast, a time zone is a history of past, present, and future changes to the offset used by the people of a certain region.
OffsetDateTime
In java.time, we represent a moment with an offset as a OffsetDateTime class.
Your input string is in standard ISO 8601 format. So we should be able to parse directly without specifying a formatting pattern, as the java.time classes use ISO 8601 formats by default when parsing/generating strings. However your input lacks a colon in the offset between hours and minutes. While allowed by the standard, the OffsetDateTime class a small bug in Java 8 & 9 that fails by default to parse such values. As a workaround, specify a DateTimeFormatter.
String input = "2018-08-22T22:00:00-0000";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ssX" ); // Specify formatting pattern to match input string.
OffsetDateTime odt = OffsetDateTime.parse( input , f ); // Parse from dumb string to smart `OffsetDateTime` object.
odt.toString(): 2018-08-22T22:00-05:00
Time zone names
How can I get the list of available Time Zone IDs?
Not sure what you mean by “Time Zone IDs”. I am guessing that you are asking for a list of all the time zones using that particular offset-from-UTC at that particular moment.
A proper time zone name has the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
We represent the time zone using the ZoneId. The TimeZone class is now legacy, and should be avoided.
To get our list of ZoneId objects with that offset in use on that date, we need to first extract the offset (ZoneOffset) from our OffsetDateTime.
ZoneOffset offset = odt.getOffset() ;
offset.toString(): -05:00
Next phase is to interrogate all known time zones, asking each for the offset in effect at the moment of our OffsetDateTime. The argument for that moment must be in UTC, a Instant object. So we must extract an Instant from our OffsetDateTime. Still the same moment, the same point on the timeline, but seen through the lens of a different wall-clock time.
Instant instant = odt.toInstant() ; // Extract a UTC value (`Instant`) from our `OffsetDateTime` object.
instant.toString(): 2018-08-23T03:00:00Z
The Z on the end is short for Zulu and means UTC.
Make an empty list to collect the desired zones.
List< ZoneId > hits = new ArrayList<>() ; // Make an empty list of `ZoneId` objects found to have our desired offset-from-UTC.
Now get all known zones. A method exists giving a set of all zone names, but not the zone objects. So for each iteration we must instantiate the ZoneId. Then we ask the zone for its rules, the list of changes in effect over time for that region. To the rules we pass our moment (Instant), and get back the ZoneOffset in effect at that time. If this offset matches our target offset, we add the zone to our list.
Be aware that many of the zones may be essentially duplicates or deprecated. The list of zones has had a fractured history, with many changes, and some are mere aliases to others.
Set < String > names = ZoneId.getAvailableZoneIds(); // Get a collection of all known time zones’ names.
for ( String name : names ) // Loop each name.
{
ZoneId z = ZoneId.of( name ); // Instantiate a `ZoneId` for that zone name.
ZoneRules rules = z.getRules(); // Get the history of past, present, and future changes in offset used by the people of this particular region (time zone).
ZoneOffset o = rules.getOffset( instant ); // Get the offset-from-UTC in effect at this moment for the people of this region.
if( o.equals( offset )) { // Compare this particular offset to see if it is the same number of hours, minutes, and seconds as our target offset.
hits.add( z ); // If we have a hit, add to our collection of `ZoneId` objects.
}
}
Dump our hits collection to the console.
[America/Panama, America/Chicago, America/Eirunepe, Etc/GMT+5, Pacific/Easter, Mexico/General, America/Porto_Acre, America/Guayaquil, America/Rankin_Inlet, US/Central, America/Rainy_River, America/Indiana/Knox, America/North_Dakota/Beulah, America/Monterrey, America/Jamaica, America/Atikokan, America/Coral_Harbour, America/North_Dakota/Center, America/Cayman, America/Indiana/Tell_City, Chile/EasterIsland, America/Mexico_City, America/Matamoros, CST6CDT, America/Knox_IN, America/Bogota, America/Menominee, America/Resolute, SystemV/EST5, Canada/Central, Brazil/Acre, America/Cancun, America/Lima, America/Bahia_Banderas, US/Indiana-Starke, America/Rio_Branco, SystemV/CST6CDT, Jamaica, America/Merida, America/North_Dakota/New_Salem, America/Winnipeg]
Be aware that this list of zones is valid only for our chosen particular moment. In earlier times, or later times, some of these zones may be using some other offset-from-UTC. Conversely, at other moments some zones not on this list may be using our desired offset.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
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.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
You can convert your date to a Calendar. Calendar.getTimeZone() would return the TimeZone match the Calendar. And then TimeZone.getAvailableIDs() would give you the available IDs.

Why does JDBC adjust the time to default timezone when it is saving a date?

This question is related to this but this specific question focuses on the why. So no, this isn't a duplicate.
Quoting the answer:
The problem is that Java Date objects don't store a time zone. The
value is always in UTC, and is parsed and formatted in a given time
zone, usually the JVM's default time zone.
Oracle DATE columns are also stored without time zone, but should
represent the date as seen by the user. In 99.99% of cases, that means
the date in the JVM's default time zone.
So, the JDBC driver takes the Timestamp / Date value, which is in UTC,
converts it to the default time zone, and saves that to the database.
What's exactly wrong with NOT adjusting and saving the value (UTC) as it is?
What is it trying to solve by adjusting the value before saving it to the database?
The answers to these questions are the whys.
I couldn't see the benefit of the design and I can only see are the problems associated with it. Case in point is when saving is done in a specific timezone and retrieval is done in another timezone. The amount of questions being thrown at this specific topic just proves my point.
So ultimate question is, why it was designed that way? What are the reasons?
Date-time handling is a surprisingly complicated topic. Our intuitive understanding of time works against us as programmers, making this topic difficult to master. Furthermore, poor date-time handling in old databases and old classes make the job even more confusing.
java.time
Firstly, avoid the wretched old date-time classes bundled with the earliest versions of Java. Never use java.util.Date, java.util.Calendar, java.sql.Timestamp, nor other related classes. Use only the java.time classes. If you must interface with old code not yet updated to java.time, call on new conversions methods added to the old classes.
Date was replaced by Instant.
The problem is that Java Date objects don't store a time zone.
Not true. An Instant (and a Date) is always in UTC. Both the modern and legacy class represent a a count of fractional seconds since the first moment of 1970 in UTC, 1970-01-01T00:00:00Z. Always in UTC, easy-peasy.
Oracle DATE columns are also stored without time zone,
True.
The Oracle DATE data type represents only a date with time zone but lacks any concept of time zone or offset-from-UTC. This is apparently a legacy type, created before the SQL standard defined some basic date-time types. In the standard, the TIMESTAMP WITHOUT TIME ZONE might map close to Oracle DATE.
but should represent the date as seen by the user. In 99.99% of cases, that means the date in the JVM's default time zone.
I have no idea what the author meant by that. I think that is their clumsy way of saying that any type similar to the SQL-standard TIMESTAMP WITHOUT TIME ZONE simply takes any given date or date-with-time-of-day as-is, with no attempt at adjusting between zones or offsets. So if you pass January 21, 2018 at noon, it stores a value equivalent to this string 2018-01-23T12:00 without any regard to whether that was noon in Montréal Québec or noon in Kolkata India (two different moments, hours apart).
So, the JDBC driver takes the Timestamp / Date value, which is in UTC, converts it to the default time zone, and saves that to the database.
While the JDBC driver is unspecified here, I doubt this is its behavior. Such behavior would be a contradiction of the behavior of the Oracle DATE type which is no such zone adjustment. The Oracle DATE type (as I read the documentation; I'm not an Oracle user) is agnostic or unaware of zones/offsets.
In Java, the class mapping to SQL-standard TIMESTAMP WITHOUT TIME ZONE and Oracle DATE is LocalDateTime. You should use these zone-less types only in these three situations:
The zone or offset is unknown.This is bad. This is faulty data. Analogous to having a price/cost without knowing the currency. You should be rejecting such data, not storing it.
The intention is “everywhere”, as in, every time zone.For example, a corporate policy that states “All our factories will break for lunch at 12:30" means the factory in Delhi will break hours before the factory in Düsseldorf which breaks hours before the factory in Detroit.
A specific moment in the future is intended, but we are afraid of politicians redefining the time zone.Governments change the rules of their time zones with surprising frequency and with surprisingly little warning or even no warning at all. So if you want to book an appointment at 3 PM on a certain date, and you really mean 3 PM regardless of any crazy decision a government might make in the interim, then store a LocalDateTime. To print a report or display a calendar, dynamically apply a time zone (ZoneId) to generate a specific moment (ZonedDateTime or Instant). This must be done on-the-fly rather than storing the value.
What's exactly wrong with NOT adjusting and saving the value (UTC) as it is?
The JDBC driver should not be doing any adjustments to UTC for a type of Oracle Date or SQL-standard TIMESTAMP WITHOUT TIME ZONE.
If two users at 2018-06-06T21:53Z, one in Québec and one in India, both simultaneously save the current moment of their own parochial wall-clock time into a column of type SQL-standard TIMESTAMP WITHOUT TIME ZONE or Oracle DATE, then we should see two rows with values:
2018-06-06T17:53 (notice the date is “yesterday”)
2018-06-07T03:23 (notice the date is “tomorrow”)
The values are different because America/Montreal is four hours behind UTC while Asia/Kolkata is five and a half hours ahead of UTC, and no adjustment for time zones was made. To repeat myself yet again, the stored values here represent only a date and a time-of-day, but without any context of time zone or offset-from-UTC, they do not represent a moment.
The confusion may be coming from the fact that some databases such a Postgres do adjust incoming values into UTC for values heading to a column of a different type, the TIMESTAMP WITH TIME ZONE type (note the WITH versus WITHOUT). Postgres and something other databases use any passed zone/offset info to adjust into UTC value, then discard the zone/offset info. So the type name is something of a misnomer, and you can think of it as TIMESTAMP WITH RESPECT FOR TIME ZONE.
If those same two users seen above at 2018-06-06T21:53Z were saving the current moment into a SQL-standard column of type TIMESTAMP WITH TIME ZONE, then the two rows would appear as:
2018-06-06T21:53Z
2018-06-06T21:53Z
The Z at the end is pronounced Zulu and means UTC.
What is it trying to solve by adjusting the value before saving it to the database?
Generally, the best practice in date-time handling is to work in UTC rather than in other zones/offsets.
When working as a programmer or sysadmin, forget about your own parochial time zone. Translating back-and-forth from your own zone to UTC or other zones will drive you batty. Think of UTC as the One True Time; all other zones are but mere variations.
The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).
Instant instant = Instant.now() ; // Capture the current moment in UTC.
Store.
String sql = "INSERT INTO tbl ( event ) VALUES ( ? ) ;" ; // Writing a moment into a column of type `TIMESTAMP WTH TIME ZONE`.
myPreparedStatement.setObject( 1 , instant ) ; // As of JDBC 4.2 and later, we can directly exchange java.time objects with our database.
Retrieve.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
Present that moment in a particular time zone.
ZoneId z = ZoneId.of( "Asia/Kolkat" ) ;
ZonedDateTime zdt = instant.atZone( z ) ; // Same moment, same point on the timeline, different wall-clock time.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
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.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

How to make date.getTime() returns UTC time?

I have a Date object which represents a UTC time. When I use the method getTime() to get the long value of this object, the value returned corresponds to our local time (central US). What is the correct way to get the value back which corresponds to the original UTC time?
Thanks
tl;dr
Instant.now()
…and…
Instant.ofEpochMilli( n )
…and…
instant.toEpochMilli()
Date is always in UTC
When I use the method getTime() to get the long value of this object, the value returned corresponds to our local time (central US).
No, the value returned from Date::getTime() always corresponds to UTC (virtually the same thing as GMT in this context). To quote the class doc:
Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT represented by this Date object.
So your Question is nonsensical in that a Date is already in UTC. No need to “get the value back which corresponds to the original UTC time”,
You may be confusing the behavior of getTime with that of the toString method. The toString method annoyingly and confusingly applies the current default time zone in the process of generating the String. So the string output appears with a time zone while in fact there is no time zone to be set or gotten from the Date itself. (There actually is a zone deep within the Date but that is irrelevant to this discussion here. This class is a confusing mess!)
java.time
The modern way to do this is using java.time classes.
Instant
The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).
Get the current moment.
Instant instant = Instant.now();
You can convert a Date to its modern replacement by calling one of the new conversion methods added to the old date-time classes. Just call toInstant, quite easy.
Instant instant = myJavaUtilDate.toInstant();
I do not recommend at all using a count-from-epoch number as a way of tracking time. Stick with the java.time objects instead. When outside Java, serialize to text use the ISO 8601 formats.
But if you must, you can extract a count of milliseconds since epoch of 1970-01-01T00:00:00Z. Note that this may involve data loss! An Instant has a finer resolution of nanoseconds. So going to milliseconds may lop off a fraction of the fraction of a second.
long millisecondsSinceEpoch = instant.toEpochMilli(); // Caution: Possible data-loss in going from nanoseconds to milliseconds.
Going the other direction, from a count to an Instant.
Instant instant = Instant.ofEpochMilli( millisecondsSinceEpoch ) ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8 and SE 9 and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
The DateFormat class has a method for setting your preferred time zone, and there's a time zone class that has a setting for UTC time.
So, for example,
SimpleDateFormat sdf = new SimpleDateFormat();
sdf.setTimeZone(new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC"));
Date yourUtcDate = sdf.parse(yourOriginalDate);
java.util.Date has no concept of timezone. It simply holds time relative to epoch, which is Jan 1 1970 00:00:00 UTC. Date is a model, separate from the view. When you display the date, the concept of timezone then is applied. Date's toString() displays a human readable date in the default timezone. You can either use a DateFormat to display a Date in a different timezone (such as UTC), or change the JVM's default timezone.
getTime() returns "the number of milliseconds since January 1, 1970, 00:00:00 GMT", nothing more, nothing less (obviously, you have to create it correctly). You can format it however you want, starting with e.g. the GregorianCalendar(TimeZone) constructor.
Most of the Date class functions are deprecated as they are now shifted in Calendar class.
Here is code to get UTC time from Calendar.
Date date = new Date(timeStamp);
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
calendar.setTime(date);
Here is the sample code to get the year, month, etc.
System.out.println(calendar.get(Calendar.YEAR));
System.out.println(calendar.get(Calendar.MONTH));
Calendar also has support for many other useful information like, TIME, DAY_OF_MONTH, etc. Here the documentation listing all of them Please note that the month are 0 based. January is 0th month.
LocalDateTime now = LocalDateTime.now(Clock.systemUTC());
Instant instant = now.atZone(ZoneId.systemDefault()).toInstant();
Date formattedDate = Date.from(instant);
return formattedDate;

Categories