Related
I have seen code where they mention UTC, i just wonder what is the syntax for US pacific time.
Calendar cal_Two = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
is it like below.
Calendar cal_Two = Calendar.getInstance(TimeZone.getTimeZone("USP"));
Prefer ZonedDateTime and ZoneId over Calendar and TimeZone
Allow me the opportunity to recommend java.time, the modern Java date and time API. I am aware that your code lines are taken out of a larger context that I don’t know, so switching to java.time may be entail a bit more work than that. It will most probably be worth it.
If you are writing new code, use java.time throughout and forget about Calendar and the other old classes.
If you are writing code that needs to interoperate with legacy code using Calendar, still consider using java.time in your own code. Straightforward conversions exist for when you need to pass a Calendar to a legacy method.
Calendar and TimeZone are poorly designed and long outdated. The modern API is so much nicer to work with and generally lends itself to more concise and more natural code that it will be much easier to maintain.
Likely America/Los_Angeles will fulfil your purpose
I believe that the America/Los_Angeles time zone covers the part of the USA that uses Pacific Time (Pacific Standard Time in the winter and Pacific Daylight Time in the summer): California, Nevada, Washington and greater parts of Oregon and Idaho.
Always give time zones in the region/city format like America/Los_Angeles or Europe/Kiev. Other formats have been used previously and are still seen, but they are no longer encouraged. Particularly a lot of two, three, four and five letter abbreviations should be avoided since they are often not true time zones and often ambiguous. Even for UTC the recommended official ID is Etc/UTC (even though Etc hardly counts as a region of the Earth).
ZoneId zone = ZoneId.of("America/Los_Angeles");
ZonedDateTime zdt = ZonedDateTime.now(zone);
System.out.println(zdt);
Output when I ran this code just now:
2020-04-23T09:35:22.842667-07:00[America/Los_Angeles]
ZonedDateTime is the most natural and general replacement for the old Calendar class, but exactly which java.time class to choose depends on your more precise requirements. Please go through the classes or a tutorial and pick the one that is right for you. One of the many advantages of ZonedDateTime over Calendar is that you get readable output when you print it.
To convert to a Calendar that you can pass to your legacy API:
Calendar calTwo = GregorianCalendar.from(zdt);
Tutorial link
Oracle tutorial: Date Time explaining how to use java.time.
No, I'm not talking about zone offsets --- those can vary during the year for a region based on e.g. DST. I'm talking about the actual time zones maintained by IANA. I understand these are not supported by ISO 8601, correct?
What are platforms doing to support identifying time zones in ISO 8601-like string representations? I notice that the latest Java date/time library is using an extended ISO 8601 format for this, e.g. 2011-12-03T10:15:30+01:00[Europe/Paris]. (See DateTimeFormatter API.)
Is there some converging convention (e.g. with other languages and platforms) for extending ISO 8601 to support time zone designation?
Update:
There's now a draft IETF proposal to extend RFC3339 with the time zone identifier in square brackets, among other things: https://datatracker.ietf.org/doc/draft-ietf-sedate-datetime-extended/
Original Answer:
I understand these are not supported by ISO 8601, correct?
Correct. ISO-8601 does not concern itself with time zone identifiers. IANA/Olson TZ names are not a "standard". They are just the most reliable thing we have. (Some may consider them the de facto standard.)
What are platforms doing to support this?
Support what exactly? This part of your question is unclear. If you mean to support IANA time zones, well that's all over the place. Some platforms have them built-in, and some rely on libraries. If you mean to support a string representation of an ISO-8601 date-time-offset + time zone ID, some platforms have this and some do not. You'll have to be more specific if you want to know more.
I notice that the latest Java date/time library is using an extended ISO 8601 format for this, e.g. 2011-12-03T10:15:30+01:00[Europe/Paris]. (See DateTimeFormatter API.)
I think you are talking about DateTimeFormatter.ISO_ZONED_DATE_TIME. The docs say specifically:
The ISO-like date-time formatter...
...extends the ISO-8601 extended offset date-time format to add the time-zone. The section in square brackets is not part of the ISO-8601 standard.
So this is Java's specific format, not a standard.
Is there some converging convention (e.g. with other languages and platforms) for extending ISO 8601 to support time zone designation?
As far as I know, there is currently no standard that covers the combining of an ISO8601 timestamp and an IANA time zone identifier into a single format. One could represent it many different ways, including:
2011-12-03T10:15:30+01:00[Europe/Paris] (this is the default in Java 8)
2011-12-03T10:15:30+01:00(Europe/Paris)
2011-12-03T10:15:30+01:00 Europe/Paris
2011-12-03T10:15:30+01:00 - Europe/Paris
2011-12-03T10:15:30+01:00/Europe/Paris
2011-12-03T10:15:30+01:00|Europe/Paris
2011-12-03T10:15:30 Europe/Paris (+01) (this is the default in Noda Time)
If what you're looking for is a way to include a ZonedDateTime or similar data in an API in a standardized manner, my personal recommendation would be to pass the time zone name in a separate field. That way, each portion of data is as good as it can be. For example in JSON:
{
"timestamp": "2011-12-03T10:15:30+01:00",
"timezone": "Europe/Paris"
}
The Answer by Matt Johnson is spot-on correct. I'll just add a few thoughts.
Time zone versus offset-from-UTC
An offset-from-UTC is merely a number of hours, minutes, and seconds ahead/behind UTC. Alone, this does make a date-time into a specific moment on the timeline. But it is not nearly as informative as including the official time zone name as well.
While there is no standard yet for including the time zone name, I do hope others follow the lead of the java.time classes in appending in square brackets the name of the time zone. This format seems sensible to me as it would be simple to truncate the square-bracket portion to be backward-compatible with non-savvy software.
For example:2011-12-03T10:15:30+01:00[Europe/Paris]. If the data were only 2011-12-03T10:15:30+01:00, we would be able to identify the moment on the timeline, but would not be able to adjust other moments into the same frame of mind as we would not know what rules of adjustment to apply. Zones such as Europe/Zagreb, Africa/Brazzaville, Arctic/Longyearbyen, and Europe/Isle_of_Man all share the offset of +01:00, but they may well have other adjustments in force differing from those of Europe/Paris. So if you were to try to add three days to the value 2011-12-03T10:15:30+01:00, you really cannot faithfully compute the result because you do not know what adjustments may need to apply such as DST cutovers that may be occurring during those three days.
A time zone defines the set of rules for handling anomalies such as Daylight Saving Time (DST). Politicians around the world enjoy making adjustments to their time zones, or even re-defining them. So these rules change frequently. Think of a time zone as a collection of offsets over time, many periods of time in history wherein each period had a particular offset in use in that particular region.
You can think of a time zone as a collection of offset-from-UTC values. In America/Los_Angeles part of this year is 8 hours behind UTC, and part of the year will be 7 hours behind UTC. That makes 2 points of data collected as part of that time zone.
Another example, in previous years, Turkey spent part of each year 2 hours ahead of UTC and part of each year 3 hours ahead. In 2016, that changed to indefinitely staying 3 hours ahead. So, multiple points of data in the time zone Europe/Istanbul.
Just use UTC
Personally I do not see much value in even using values such as 2011-12-03T10:15:30+01:00. Without a time zone, you might just as well use UTC alone. In this case, 2011-12-03T09:15:30Z (9 AM instead of 10 AM).
Generally the best practice is to use UTC when storing and exchanging date-time values. Think of UTC as the One-True-Time, with zoned or offset values being mere variations.
I'm developing a Java application with a MySQL database on a server located in a different time zone from mine, and I am trying to decide between using DATETIME or TIMESTAMP on my database.
After reading questions like Should I use field 'datetime' or 'timestamp'?, and the MySQL documentation, I decided TIMESTAMP was better for me as it converts values to UTC for storage, and back to the current time zone for retrieval.
Also, as user Jesper explains in this thread, java.util.Date objects are internally only a UTC timestamp (i.e. number of milliseconds since the Epoch), and when you do a toString() it is displayed according to your current time zone.
For me, that looks like a good practice: storing datetimes as UTC timestamps, and then displaying them according to the current time zone.
I was about to do it like that, but then I found this from the Java documentation for Prepared Statements and got very confused:
void setTimestamp(int parameterIndex,
Timestamp x,
Calendar cal)
throws SQLException
Sets the designated parameter to the given java.sql.Timestamp value,
using the given Calendar object. The driver uses the Calendar object
to construct an SQL TIMESTAMP value, which the driver then sends to
the database. With a Calendar object, the driver can calculate the
timestamp taking into account a custom timezone. If no Calendar object
is specified, the driver uses the default timezone, which is that of
the virtual machine running the application.
Before this, I thought timestamps were by convention always in UTC. Why on earth would anyone want a localized timestamp instead of a localized representation of it? Wouldn't that be very confusing for everyone?
How do these conversions work? If Java takes an UTC timestamp and converts it to an arbitrary time zone, how can it tell MySQL in which timezone it is?
Won't MySQL assume that this timestamp is in UTC and then retrieve an incorrect localized value?
Date-Time Handling Is A Mess
The first paragraph in the answer by Teo is quite insightful and correct: Date-time handling in Java is a mess. Ditto for all other languages & development environments that I know of. Date-time work is difficult and tricky, especially error-prone and frustrating because we think it of date-time intuitively. But "intuitively" does not cut it when it comes to data types, databases, serialization, localization, adjusting across time zones, and all the other formalities that come with computer programming.
Unfortunately, the computer industry basically chose to ignore this problem of date-time work. Just as Unicode took too long to be invented given the obvious need, so too has the industry kicked the can down the road on solving the problem of date-time handling.
Do Not Rely On Count-Since-Epoch
But I must disagree with its conclusion. Working with a count-since-epoch is not the best solution. Using count-since-epoch is inherently confusing and error-prone and incompatible.
Humans cannot read a long number and decipher that as a date-time. So verifying data and debugging becomes complicated, to say the least.
What "count" would you use? The milliseconds used by java.util.Date and by Joda-Time? The microseconds used by Postgres, MySQL, and other databases? The nanoseconds used by the new java.time package in Java 8?
Which epoch would you use? The Unix epoch of the beginning of 1970 in UTC is common, but far from singular. Almost two dozen epochs have been used by various computer systems.
We create numeric data types for doing math rather than using bits. We create string classes to handle the nitty-gritty details of handling text rather than bare octets. So too we should create data-types and classes to handle date-time values.
The early Java teams (and IBM & Taligent before them) made an attempt with the java.util.Date and java.util.Calendar and related classes. Unfortunately, the attempt was inadequate. While date-time is inherently confusing, these classes have added even more confusion.
Joda-Time
As far as I know, the Joda-Time project was the first project to take on date-time in a thorough, competent, and successful manner. Even so, the creators of Joda-Time were not entirely satisfied. They went on to create the java.time package in Java 8, and extend that work with the threeten-extra project. Joda-Time and java.time share similar concepts but are distinct, each having some advantages.
Database Problems
Specifically, the java.util.Date & .Calendar classes lack date-only values without time-of-day and time zone. And they lack time-only values without date and time zone. Before Java 8, the Java team added the hacks known as the java.sql.Date and java.sql.Time classes which is a date-time value masquerading as a date-only. Both Joda-Time and java.time rectify that by offering LocalDate and LocalTime classes.
Another specific problem is that java.util.Date has a resolution of milliseconds, but databases frequently use microseconds or nanoseconds. In an ill-advised attempt to bridge this disparity, the early Java team created another hack, the java.sql.Timestamp class. While technically a java.util.Date subclass, it also tracks the fractional seconds to nanosecond resolution. So when converting in and out of this type you may losing or gaining the finer fractional seconds granularity without being conscious of that fact. So that might mean that values you expect to be equal are not.
Another source of confusion is the SQL data type, TIMESTAMP WITH TIME ZONE. That name is a misnomer as the time zone info is not stored. Think of the name as TIMESTAMP WITH RESPECT FOR TIME ZONE as any passed time zone offset info is used in converting the date-time value to UTC.
The java.time package with its nanosecond resolution has some specific features to better communicate date-time data with a database.
I could write much more, but such information can be gleaned from searching StackOverflow for words such as joda, java.time, sql timestamp, and JDBC.
Example using Joda-Time with JDBC with Postgres. Joda-Time uses immutable objects for thread-safety. So rather than alter an instance ("mutate"), we create a fresh instance based on the values of the original.
String sql = "SELECT now();";
…
java.sql.Timestamp now = myResultSet.getTimestamp( 1 );
DateTime dateTimeUtc = new DateTime( now , DateTimeZone.UTC );
DateTime dateTimeMontréal = dateTimeUtc.withZone( DateTimeZone.forID( "America/Montreal" ) );
Focus On UTC
Before this, I thought timestamps were by convention always in UTC. Why on earth would anyone want a localized timestamp instead of a localized representation of it? Wouldn't that be very confusing for everyone?
Indeed. The SQL standard defines a TIMESTAMP WITHOUT TIME ZONE which ignores and strips away any included time zone data. I cannot imagine the usefulness of that. This Postgres expert, David E. Wheeler, says as much in recommending always using TIMESTAMP WITH TIME ZONE. Wheeler cites one narrow technical exception (partitioning) and even then says to convert all the values to UTC yourself before saving to the database.
The best practice is to work and store data in UTC while adjusting to localized time zones for presentation to the user. There may be times when you want to remember the original date-time data in its localized time zone; if so, save that value in addition to converting to UTC.
Guidelines
The first steps to better date-time handling are avoiding java.util.Date & .Calendar, using Joda-Time and/or java.time, focusing on UTC, and learning the behavior of your specific JDBC driver and your specific database (databases vary widely in their date-time handling despite the SQL standard).
MySQL
Caveat: I don’t use MySQL (I'm a Postgres kind of guy).
According to the version 8 documentation, the two types DATETIME and TIMESTAMP differ in that the first one lacks any concept of time zone or offset-from-UTC. The second one uses any indication of time zone or offset-from-UTC accompanying an input to adjust that value to UTC, then stores it, and discards the zone/offset info.
So these two types seem to be akin to the standard SQL types:
MySQL DATETIME ≈ SQL-standard TIMESTAMP WITHOUT TIME ZONE
MySQL TIMESTAMP ≈ SQL-standard TIMESTAMP WITH TIME ZONE
For MySQL DATETIME, use the Java class LocalDateTime. That class, like that data type, purposely lacks any concept of time zone or offset-from-UTC. Use this type and class for either:
When you mean any zone or all zones, such as “Christmas starts on first moment of December 25, 2018”. That translates to different moments in different places as a new day dawns earlier in the east than in the west.
When scheduling appointments or events far enough out in the future that politicians may change the offset of the time zone, for which politicians around the world have shown a proclivity. In this usage, you must at runtime apply a time zone to dynamically calculate, but not store, a moment for display on a calendar. That way, a 15:00 dental appointment in 8 months remains at 15:00 even if politicians redefine the clock to be minutes/hours ahead or behind.
For MySQL TIMESTAMP, use the Java class Instant, as shown above. Use this type and class for moments, specific point on the timeline.
JDBC 4.2
As of JDBC 4.2 and later, we can directly exchange java.time objects with the database. Use getObject & setObject methods.
myPreparedStatement.setObject( … , Instant.now() ) ;
Retrieval.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
The JDBC 4.2 specification requires a driver to support OffsetDateTime but strangely does not require support for the more common types Instant and ZonedDateTime. But converting between types is quite easy.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Instant instant = odt.toInstant() ;
You can then adjust that UTC value in Instant to a specific time zone for presentation to a user.
ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
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.
Your question is spot on a problem which i think is huge these days. Both DB (via SQL) and server side itself (via programming languages such as Java) offer a compendium of ways of dealing with date and time. I would qualify the status-quo as highly non-standardized and a bit chaotic (personal opinion :)
My answer is partial but i'll explain why.
You're correct, Java's Date (and Calendar) store time as milliseconds since the Unix Epoch (which is great). It happens not only in Java but in other programming languages as well. In my opinion the perfect time-keeping architecture emerges naturally from this: the Unix Epoch is January 1st, 1970, midnight, UTC. Therefore if you choose to store time as milliseconds since the Unix Epoch you have a lot of benefits:
architecture clarity: server side works with UTC, client side shows the time through its local timezone
database simplicity: you store a number (milliseconds) rather than complex data structures like DateTimes
programming efficiency: in most programming languages you have date/time objects capable of taking milliseconds since Epoch when constructed (which as you said, allows for automatic conversion to client-side timezone)
I find code and architecture is much simpler and more flexible when using this approach. I stopped trying to understand things like DateTime (or Timestamp) and only deal with them when i have to fix legacy code.
Could someone please advise the current "best practice" around Date and Calendar types.
When writing new code, is it best to always favour Calendar over Date, or are there circumstances where Date is the more appropriate datatype?
Date is a simpler class and is mainly there for backward compatibility reasons. If you need to set particular dates or do date arithmetic, use a Calendar. Calendars also handle localization. The previous date manipulation functions of Date have since been deprecated.
Personally I tend to use either time in milliseconds as a long (or Long, as appropriate) or Calendar when there is a choice.
Both Date and Calendar are mutable, which tends to present issues when using either in an API.
The best way for new code (if your policy allows third-party code) is to use the Joda Time library.
Both, Date and Calendar, have so many design problems that neither are good solutions for new code.
Date and Calendar are really the same fundamental concept (both represent an instant in time and are wrappers around an underlying long value).
One could argue that Calendar is actually even more broken than Date is, as it seems to offer concrete facts about things like day of the week and time of day, whereas if you change its timeZone property, the concrete turns into blancmange! Neither objects are really useful as a store of year-month-day or time-of-day for this reason.
Use Calendar only as a calculator which, when given Date and TimeZone objects, will do calculations for you. Avoid its use for property typing in an application.
Use SimpleDateFormat together with TimeZone and Date to generate display Strings.
If you're feeling adventurous use Joda-Time, although it is unnecessarily complicated IMHO and is soon to be superceded by the JSR-310 date API in any event.
I have answered before that it is not difficult to roll your own YearMonthDay class, which uses Calendar under the hood for date calculations. I was downvoted for the suggestion but I still believe it is a valid one because Joda-Time (and JSR-310) are really so over-complicated for most use-cases.
tl;dr
advise the current "best practice" around Date and Calendar
is it best to always favour Calendar over Date
Avoid these legacy classes entirely. Use java.time classes instead.
For a moment in UTC, use Instant(the modern equivalent of Date)
For a moment in a particular time zone, use ZonedDateTime(the modern equivalent of GregorianCalendar)
For a moment in a particular offset-from-UTC, use OffsetDateTime(no equivalent in legacy classes)
For a date-time (not a moment) with unknown time zone or offset, use LocalDateTime(no equivalent in legacy classes)
Details
The Answer by Ortomala Lokni is right to suggest using the modern java.time classes rather than the troublesome old legacy date-time classes (Date, Calendar, etc.). But that Answer suggests the wrong class as equivalent (see my comment on that Answer).
Using java.time
The java.time classes are a vast improvement over the legacy date-time classes, night-and-day difference. The old classes are poorly-designed, confusing, and troublesome. You should avoid the old classes whenever possible. But when you need to convert to/from the old/new, you can do so by calling new methods add to the old classes.
For much more information on conversion, see my Answer and nifty diagram to another Question, Convert java.util.Date to what “java.time” type?.
Searching Stack Overflow gives many hundreds of example Questions and Answers on using java.time. But here is a quick synopsis.
Instant
Get the current moment with an 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).
Instant instant = Instant.now();
ZonedDateTime
To see that same simultaneous moment through the lens of some particular region’s wall-clock time, apply a time zone (ZoneId) to get a ZonedDateTime.
Time zone
Specify a proper time zone name in 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(!).
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone();
Offset
A time zone is a region’s history of changes in its offset-from-UTC. But sometimes you are given only an offset without the full zone. In that case, use the OffsetDateTime class.
ZoneOffset offset = ZoneOffset.parse( "+05:30" );
OffsetDateTime odt = instant.atOffset( offset );
Use of a time zone is preferable over use of a mere offset.
LocalDateTime
The “Local” in the Local… classes means any locality, not a particular locality. So the name can be counter-intuitive.
LocalDateTime, LocalDate, and LocalTime purposely lack any information about offset or time zone. So they do not represent actual moments, they are not points on the timeline. When in doubt or in confusion, use ZonedDateTime rather than LocalDateTime. Search Stack Overflow for much more discussion.
Strings
Do not conflate date-time objects with strings that represent their value. You can parse a string to get a date-time object, and you can generate a string from a date-time object. But the string is never the date-time itself.
Learn about standard ISO 8601 formats, used by default in the java.time classes.
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.
Using a JDBC driver compliant with JDBC 4.2 or later, you may exchange java.time objects directly with your database. No need for strings nor 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.
Date is best for storing a date object. It is the persisted one, the Serialized one ...
Calendar is best for manipulating Dates.
Note: we also sometimes favor java.lang.Long over Date, because Date is mutable and therefore not thread-safe. On a Date object, use setTime() and getTime() to switch between the two. For example, a constant Date in the application (examples: the zero 1970/01/01, or an applicative END_OF_TIME that you set to 2099/12/31 ; those are very useful to replace null values as start time and end time, especially when you persist them in the database, as SQL is so peculiar with nulls).
I generally use Date if possible. Although it is mutable, the mutators are actually deprecated. In the end it basically wraps a long that would represent the date/time. Conversely, I would use Calendars if I have to manipulate the values.
You can think of it this way: you only use StringBuffer only when you need to have Strings that you can easily manipulate and then convert them into Strings using toString() method. In the same way, I only use Calendar if I need to manipulate temporal data.
For best practice, I tend to use immutable objects as much as possible outside of the domain model. It significantly reduces the chances of any side effects and it is done for you by the compiler, rather than a JUnit test. You use this technique by creating private final fields in your class.
And coming back to the StringBuffer analogy. Here is some code that shows you how to convert between Calendar and Date
String s = "someString"; // immutable string
StringBuffer buf = new StringBuffer(s); // mutable "string" via StringBuffer
buf.append("x");
assertEquals("someStringx", buf.toString()); // convert to immutable String
// immutable date with hard coded format. If you are hard
// coding the format, best practice is to hard code the locale
// of the format string, otherwise people in some parts of Europe
// are going to be mad at you.
Date date = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse("2001-01-02");
// Convert Date to a Calendar
Calendar cal = Calendar.getInstance();
cal.setTime(date);
// mutate the value
cal.add(Calendar.YEAR, 1);
// convert back to Date
Date newDate = cal.getTime();
//
assertEquals(new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse("2002-01-02"), newDate);
Dates should be used as immutable points in time; Calendars are mutable, and can be passed around and modified if you need to collaborate with other classes to come up with a final date. Consider them analogous to String and StringBuilder and you'll understand how I consider they should be used.
(And yes, I know Date isn't actually technically immutable, but the intention is that it should not be mutable, and if nothing calls the deprecated methods then it is so.)
With Java 8, the new java.time package should be used.
Objects are immutable, time zones and day light saving are taken into account.
You can create a ZonedDateTime object from an old java.util.Date object like this:
Date date = new Date();
ZonedDateTime zonedDateTime = date.toInstant().atZone(ZoneId.systemDefault());
I always advocate Joda-time. Here's why.
the API is consistent and intuitive. Unlike the java.util.Date/Calendar APIs
it doesn't suffer from threading issues, unlike java.text.SimpleDateFormat etc. (I've seen numerous client issues relating to not realising that the standard date/time formatting is not thread-safe)
it's the basis of the new Java date/time APIs (JSR310, scheduled for Java 8. So you'll be using APIs that will become core Java APIs.
EDIT: The Java date/time classes introduced with Java 8 are now the preferred solution, if you can migrate to Java 8
A little bit late at party, but Java has a new Date Time API in JDK 8. You may want to upgrade your JDK version and embrace the standard. No more messy date/calendar, no more 3rd party jars.
Date should be re-developed. Instead of being a long interger, it should hold year, month, date, hour, minute, second, as separate fields. It might be even good to store the calendar and time zone this date is associated with.
In our natural conversation, if setup an appointment at Nov. 1, 2013 1pm NY Time, this is a DateTime. It is NOT a Calendar. So we should be able to converse like this in Java as well.
When Date is stored as a long integer (of mili seconds since Jan 1 1970 or something), calculating its current date depends on the calendar. Different calendars will give different date. This is from the prospective of giving an absolute time (eg 1 trillion seconds after Big Bang). But often we also need a convenient way of conversation, like an object encapsulating year, month etc.
I wonder if there are new advances in Java to reconcile these 2 objectives. Maybe my java knowledge is too old.
Btw "date" is usually tagged as "obsolete / deprecated" (I dont know exactly why) - something about it is wrote there
Java: Why is the Date constructor deprecated, and what do I use instead?
It looks like it's a problem of the constructor only- way via new Date(int year, int month, int day), recommended way is via Calendar and set params separately .. (Calendar cal = Calendar.getInstance();
)
I use Calendar when I need some specific operations over the dates like moving in time, but Date I find it helpful when you need to format the date to adapt your needs, recently I discovered that Locale has a lot of useful operations and methods.So I'm using Locale right now!
This question already has answers here:
Java Best Practice for Date Manipulation/Storage for Geographically Diverse Users
(2 answers)
Closed 1 year ago.
What is the best practice for manipulating and storing Dates e.g. using GregorianCalendar in an enterprise java application?
Looking for feedback and I will consolidate any great answers into a best practice that others can use.
The best practice is usually precisely NOT to think in term of heavy date objects but to store a point in time. This is typically done by storing a value that doesn't suffer from corner cases nor from potential parsing problems. To do this, people usually store the number of milliseconds (or seconds) elapsed since a fixed point that we call the epoch (1970-01-01). This is very common and any Java API will always allow you to convert any kind of date to/from the time expressed in ms since the epoch.
That's for storage. You can also store, for example, the user's preferred timezone, if there's such a need.
Now such a date in milliseconds, like:
System.out.println( System.currentTimeMillis() );
1264875453
ain't very useful when it's displayed to the end user, that's for granted.
Which is why you use, for example, the example Joda time to convert it to some user-friendly format before displaying it to the end-user.
You asked for best practice, here's my take on it: storing "date" objects in a DB instead of the time in milliseconds is right there with using floating point numbers to represent monetary amounts.
It's usually a huge code smell.
So Joda time in Java is the way to manipulate date, yes. But is Joda the way to go to store dates? CERTAINLY NOT.
Joda is the way to go. Why ?
it has a much more powerful and intuitive interface than the standard Date/Time API
there are no threading issues with date/time formatting. java.text.SimpleDateFormat is not thread-safe (not a lot of people know this!)
At some stage the Java Date/Time API is going to be superseded (by JSR-310). I believe this is going to be based upon the work done by those behind Joda, and as such you'll be learning an API that will influence a new standard Java API.
Joda time (100% interoperable with the JDK)
Joda-Time provides a quality replacement for the Java date and time classes. The design allows for multiple calendar systems, while still providing a simple API
UTC
Think, work, and store data in UTC rather than any time zone. Think of UTC as the One True Time, and all other time zones are mere variations. So while coding, forget all about your own time zone. Do your business logic, logging, data storage, and data exchange in UTC. I suggest every programmer keep a second clock on their desk set to UTC.
java.time
The modern way is the java.time classes.
The mentioned Joda-Time project provided the inspiration for the java.time classes, and the project is now in maintenance mode with the team advising migration to java.time classes.
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, & java.text.SimpleDateFormat.
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.
ISO 8601
When serializing a date-time value to text, use the ISO 8601 standard.
For example, a date-time in UTC is 2016-10-17T01:24:35Z where the Z is short for Zulu and means UTC. For other offset-from-UTC the offset of hours and minutes appears at the end such as 2016-01-23T12:34:56+05:30. The java.time classes extend this standard format to append the name of the time zone (if known) in square brackets, such as 2016-01-23T12:34:56+05:30[Asia/Kolkata].
The standard has many other handy formats as well including for durations, intervals, ordinals, and year-week.
Database
For database storage, use date-time types for date-time values, such as the SQL standard data types which are primarily DATE, TIME, and TIMESTAMP WITH TIME ZONE.
Let your JDBC driver do the heavy lifting. The driver handles the nitty-gritty details about mediating and adapting between the internals of how Java handles the data and how your database handles the data on its side. But be sure to practice with example data to learn the behaviors of your driver and your database. The SQL standard defines very little about date-time handling and so behaviors vary widely, surprisingly so.
If using a JDBC driver compliant with JDBC 4.2 and later, you can fetch and store java.time types directly via the ResultSet::getObject and PreparedStatement::setObject methods.
Instant instant = myResultSet.getObject( … );
myPreparedStatement.setObject( … , instant );
For older drivers, you will need to fall back to converting through the java.sql types. Look for new conversion methods added to the old classes. For example, java.sql.Timestamp.toInstant().
Instant instant = myResultSet.getTimestamp( … ).toInstant();
myPreparedStatement.setObject( … , java.sql.Timestamp.from( instant ) );
Use the java.sql types as briefly as possible. They are a badly designed hack, such as java.sql.Date masquerading as a date-only value but actually as a subclass of java.util.Date it does indeed have a time-of-day set to the 00:00:00 in UTC. And, oh, you are supposed to ignore the fact of that inheritance says the class doc. An ugly mess.
Example code
Get the current moment in UTC.
Instant instant = Instant.now();
Storing and fetching that Instant object to/from a database is shown above.
To generate an ISO 8601 string, merely call toString. The java.time classes all use ISO 8601 formats by default for parsing and generating strings of their various date-time values.
String output = instant.toString();
Adjust into any offset-from-UTC by applying a ZoneOffset to get an OffsetDateTime. Call toString to generate a String in ISO 8601 format.
ZoneOffset offset = ZoneOffset.ofHoursMinutes( 5 , 30 );
OffsetDateTime odt = instant.atOffset( offset );
A time zone is an offset plus a set of rules for handling anomalies such as Daylight Saving Time (DST). When you need to see that same moment through the lens of some region’s own wall-clock time, apply a time zone (ZoneId) to get a ZonedDateTime object.
Specify a proper time zone name in the format of continent/region. 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(!).
ZoneId z = ZoneId.of( "Asia/Kolkata" );
ZonedDateTime zdt = instant.atZone( z );
Going the other direction, you can extract an Instant from an OffsetDateTime or ZonedDateTime by calling toInstant.
Instant instant = zdt.toInstant();
Formatting
For presentation to the user as strings in formats other than ISO 8601, search Stack Overflow for use of the DateTimeFormatter class.
While you can specify an custom format, usually best to let java.time automatically localize. To localize, specify:
FormatStyle to determine how long or abbreviated should the string be.
Locale to determine (a) the human language for translation of name of day, name of month, and such, and (b) the cultural norms deciding issues of abbreviation, capitalization, punctuation, and such.
Example:
Locale l = Locale.CANADA_FRENCH ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( l );
String output = zdt.format( f );
Conversion
Best to avoid the legacy date-time types whenever possible. But if working with old code not yet updated for the java.time types, you can convert to/from the java.time types. For details, see the Question, Convert java.util.Date to what “java.time” type?.
Use objects
Use objects rather than mere coded primitives and simple strings. For example:
Do not use 1-7 to represent a day-of-week, use the DayOfWeek enum such as DayOfWeek.TUESDAY.
Rather than passing around a string as a date, pass around LocalDate objects.
Rather than pass around a pair of integers for a year-and-month, pass around YearMonth objects.
Instead of 1-12 for a month, use the much more readable Month enum such as Month.JANUARY.
Using such objects makes your code more self-documenting, ensures valid values, and provides type-safety.
To get the discussion started, here's been my experience:
When creating standards for a typical 3-tier Java Enterprise project, I would generally recommend that the project use GregorianCalendar for manipulating dates. Reason is GregorianCalendar is the de facto standard over any other Calendar instance e.g. Julian calendar etc. It's the recognized calendar in most countries and properly handles leap years, etc. On top of that, I would recommend that the application store its dates as UTC so that you can easily perform date calculations such as finding the difference between two dates (if it were stored as EST for example, you'd have to take day light savings time into account). The date can be then be localized to whatever timezone you need it to be displayed to the user as -- such as localizing it to EST if you are an east-coast US company and you want your time information shown in EST.