I have a Java Application running in my Ubuntu Server in USA and configure CEST Time Zone.
If I run Date command in terminal it return date in CEST Zone time - this is perfect.
But In Java if I run the following code
System.out.println (new Date ());
It returns me time in EDT. What configuration am I missing.
You have to be careful in interpreting date objects from the display you get in console because they are formatted using the default TimeZone of the VM on which this program is running (which by default inherits it from timezone of OS).
Of course you can supply your own TimeZone as explained in the answer by Jesper. But while doing so I would strongly recommend to use IANA timezone identifiers like America/New_York instead of EST. More so because abbreviations having "standard" do not take into account day light savings.
So if you simply print the date object on console and you are not getting expected result, chances are high that you have your server timezone is set to wrong value or your OS is set at wrong timezone.
For changing the JVM timezone you can use this parameter on startup
-Duser.timezone="America/New_York"
You say the server is configured to be in the CEST timezone, but according to Java the default timezone is EDT. Java gets the default timezone from the operating system, so probably your server is not properly set to be in CEST.
If you want to print the date in a specific timezone, use a DateFormat and set the timezone on it:
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
df.setTimeZone(TimeZone.getTimeZone("CET"));
System.out.println(df.format(new Date()));
Note: CEST is not a valid timezone according to my Java (Java 7u45). Did you mean "CET"? (CEST is the summertime variant of CET, but if you use CET, Java will automatically display the time in summertime if appropriate).
tl;dr
UTC:
Instant.now() // Instantiate an object capturing the current moment in UTC.
.toString() // Generate a String representing textually that date-time value using standard ISO 8601 format.
2018-03-16T00:57:34.233762Z
Zoned:
ZonedDateTime.now( ZoneId.of( "Africa/Tunis" ) ) // Instantiate an object representing the current moment with a wall-clock time seed by people in a particular region (time zone).
.toString() // Generate a String representing textually that date-time value using standard ISO 8601 format wisely extended to append the name of the time zone in square brackets.
2018-03-16T01:57:34.233762+01:00[Africa/Tunis]
Details
The Answer by Shailendra is spot-on correct.
In addition, the Date class seen in the Question is part of the troublesome old date-time classes that are now legacy, supplanted entirely by the java.time classes.
The replacement for java.util.Date is java.time.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::toString ➞ UTC always
When calling the legacy class’ Date::toString method, the unfortunate behavior chosen by its authors is to dynamically apply your JVM’s current default time zone. This creates no end of confusion. Fortunately, the modern class tells the simple truth without adding any time zone: An Instant is always in UTC.
Instant.now().toString()
2018-03-16T00:57:34.233762Z
That strings format is standard ISO 8601 format. The Z on the end is short for Zulu and means UTC.
CEST Zone time
There is no such thing as a time zone named CEST. Such 3-4 letter names are pseudo-zones. They are not standardized. They are not unique(!). Instead use a proper time zone in format of continent/region.
ZoneId z = ZoneId.of( "Europe/Paris" ) ;
You can adjust from UTC to such a time zone by applying a ZoneId to your Instant to get a ZoneDateTime.
Instant instant = Instant.now() ;
ZonedDateTime zdt = instant.atZone( z ) ;
zdt.toString(): 2018-03-16T01:57:34.233762+01:00[Europe/Paris]
Or use the shortcut, ZonedDateTime.now.
ZonedDateTime zdt = ZonedDateTime.now( z ) ;
You can adjust a ZonedDateTime to another time zone as well. Notice that java.time uses immutable objects. So in adjusting we get a new distinct object based on the original but without disturbing the original.
ZoneId zNewYork = ZoneId.of( "America/New_York" ) ;
ZonedDateTime zdtNewYork = zdt.withZoneSameInstant( zNewYork ) ;
zdtNewYork.toString(): 2018-03-15T20:57:34.233762-04:00[America/New_York]
Be very clear that instant, zdt, and zdtNewYork are three separate objects that represent the very same moment, the same point on the timeline. Same moment, different wall-clock time.
I have a Java Application running in my Ubuntu Server in USA and configure CEST Time Zone
FYI, generally speaking, the best practice for a server’s default time zone is UTC.
More importantly, the current default time zone of your server OS and JVM should be irrelevant to your Java app.
Rather than rely implicitly on the JVM’s current default time zone, always specify explicitly the desired/expected time zone. Pass the optional ZoneId argument to the various java.time methods as seen in the code above.
(By the way, ditto for Locale - always specify desired/expected locale rather than rely implicitly on current default.)
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 (<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.
Related
Other system send for us Timestamp in their time zone.If we run that in cloud in other system is +2 hours. Local is good because the server is the same time zone. How can I be sure that the time will always be right?
String TIME_STAMP_FORMAT = "yyyy-MM-dd-HH.mm.ss.SSSSSS";
DateTimeFormatter TIME_STAMP_FORMATTER = DateTimeFormatter.ofPattern(TIME_STAMP_FORMAT, Locale.getDefault());
private static Timestamp parseTimestamp(String dateString) {
try {
return Timestamp.valueOf(LocalDateTime.parse(dateString, TIME_STAMP_FORMATTER));
} catch (DateTimeParseException e) {
log.error("Not able to parse timestamp", e);
}
return null;
}
Date afterParse = parseTimestamp('2018-12-31-12.30.50.000200')
tl;dr
How can I be sure that the time will always be right?
Include an indicator of time zone or offset-from-UTC with your date-time input string.
Use standard ISO 8601 formats when exchanging date-time values.
Use only java.time classes in Java. Never use Date, Timestamp, Calendar, etc.
Tip: Adjust values from other zones to UTC before sending (generally speaking).
If not possible, then here is a workaround. This assumes you know the time zone intended by the sender of this poor data.
LocalDateTime // Represent a date and time-of-day without the context of a time zone or offset-from-UTC. NOT a moment, NOT a point on the timeline. A meaningless value until you assign a zone/offset.
.parse(
"2018-12-31-12.30.50.000200" , // Avoid such custom formats. Use only ISO 8601 when exchanging date-time values textually.
DateTimeFormatter.ofPattern( "uuuu-MM-dd-HH.mm.ss.SSSSSS" ) // Define formatting pattern to match youre input.
) // Returns a `LocalDateTime` object.
.atZone( // Give meaning to the `LocalDateTime` object by applying a time zone.
ZoneId.of( "Africa/Tunis" ) // Always specify a time zone with `Continent/Region` name, never the 2-4 character pseudo-zones popularly seen in the media.
) // Returns a `ZonedDateTime` object.
.toInstant() // Adjust from a time zone to UTC by extracting an `Instant` object. Same moment, same point on the timeline, different wall-clock time.
See this code run live at IdeOne.com.
Best to avoid java.util.Date class. But if you must interoperate with old code not yet updated to java.time, you can convert. Call on the new methods added to the old classes such as Date.from( Instant ).
Avoid legacy classes
Never use java.sql.Timestamp nor java.util.Date. All of the date-time classes bundled with the earliest versions of Java are now legacy, per the adoption of JSR 310. Use only the modern java.time classes.
Wrong data type
You are using the wrong data type. To track a moment, a specific point on the timeline, you must have a time zone or offset-from-UTC. The LocalDateTime class exactly the wrong class to use here. That class purposely lacks any concept of zone or offset. So it is the opposite of what you want.
To track a moment, use Instant, OffsetDateTime, or ZonedDateTime.
Where the java.time classes have methods with an optional time zone (ZoneId) or offset-from-UTC (ZoneOffset) argument, consider the argument required. Always pass a zone/offset. Then you never need worry about how the sysadmin is setting the JVM’s current default time zone at runtime.
ZonedDateTime.now( // Capture the current moment as seen through the wall-clock time used by the people of a particular region (a time zone).
ZoneId.of( "Pacific/Auckland" )
)
Or, use Instant which is always in UTC, by definition.
Instant.now() // Capture the current moment in UTC.
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(!).
ISO 8601
Your question is not clear, but it seems you are receiving an input string for a date-time in a custom format. I suggest you educate the people publishing that data about the ISO 8601 standard. This standard defines practical formats for date-time values being exchanged between systems textually.
The java.time classes use the ISO 8601 formats by default when parsing/generating strings.
Workaround
If the data publisher is sending you values such as 2018-12-31-12.30.50.000200 in order to communicate a moment, they have failed. A date and time-of-day without a zone or offset is useless, like communicating an amount of money without indicating a currency.
Do you know for certain the time zone that was implicitly assumed by the sender of this faulty data input? If so, apply it, as a clumsy stop-gap measure for their poor practice.
First parse your input as a LocalDateTime given that it lacks any indicator of zone/offset.
String input = "2018-12-31-12.30.50.000200" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd-HH.mm.ss.SSSSSS" ) ;
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;
Apply a ZoneId to get a ZonedDateTime object, thereby adjusting to view the moment through the wall-clock time used by the people of that particular region.
ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = ldt.atZone( ldt ) ;
Generally best to work with moments in UTC, unless you have a specific reason to use a time zone (such as presentation to user). So extract an Instant from your ZonedDateTime.
Instant instant = zdt.toInstant() ;
The Z at the end of an ISO 8601 compliant string means UTC, and is pronounced “Zulu”.
See this code run live at IdeOne.com.
input: 2018-12-31-12.30.50.000200
ldt: 2018-12-31T12:30:50.000200
zdt: 2018-12-31T12:30:50.000200+09:00[Asia/Tokyo]
instant: 2018-12-31T03:30:50.000200Z
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.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
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.
Just a small supplement to Basil Bourque’s clever and very informative answer.
I know the date is in CET timezone.
I am sorry, this is not enough. Central European Time (CET) is the common term for quite many European and African(!) time zones the details of which differ. The European ones are generally at offset +01:00 during standard time and at +02:00 during summer (known as Central European Summer Time or CEST). The African ones are at +01:00 all year. For past dates, just a few decades back, some zones used summer time (DST), others didn’t, some were at +00:00, +01:00 or +02:00, and further back in history many other offsets were used, generally not whole hours.
The future is even worse! It has been suggested that the European Union abandons summer time and leaves it to each member state whether they will use permanent standard time or permanent summer time, avoiding the time adjustments in spring and autumn. There is a power struggle going on about this, so we don’t know whether it will happen, nor what each member state chooses. So even if you could tell me the exact time zone of your string from the other system (for example, Europe/Sarajevo), no one knows yet whether 2019-11-01-00.30.50.000200 — less than 7 months from now — will be at offset +01:00 or +02:00.
Link: European MPs vote to end summer time clock changes on BBC News.
I am attempting to show transactions over a certain time period using Jodatime.
Our server requires a start date and end date to be in UTC (which is probably obvious). Therefore any business logic around these is using DateTime object with the timezone set to DateTimeZone.UTC, e.g.
mStartDate = DateTime.now(UTC).withTimeAtStartOfDay();
That works well except when it comes to display the time I don't know how to augment it for the local (system default) timezone. Ideally I would like to use the DateUtils formatDateRange function passing in two local timestamps. But the getMillis() function doesn't seem to account for local offsets:
I have also tried this:
mTimePeriodTitle.setText(DateUtils.formatDateRange(mContext, f, mStartDate.getMillis(),
mEndDate.getMillis(), DateUtils.FORMAT_SHOW_TIME,
TimeZone.getDefault().getID()).toString());
But it hasn't made any difference. So my question is how can I get a nicely formatted local date range with 2 UTC timestamps?
If your DateTime is in UTC and you want to convert it to another timezone, you can use the withZone method to do the conversion.
For the examples below, my default timezone is America/Sao_Paulo (you can check yours using DateTimeZone.getDefault()):
// create today's date in UTC
DateTime mStartDate = DateTime.now(DateTimeZone.UTC).withTimeAtStartOfDay();
// date/time in UTC
System.out.println(mStartDate); // 2017-06-13T00:00:00.000Z
// date/time in my default timezone (America/Sao_Paulo)
System.out.println(mStartDate.withZone(DateTimeZone.getDefault())); // 2017-06-12T21:00:00.000-03:00
The output is:
2017-06-13T00:00:00.000Z
2017-06-12T21:00:00.000-03:00
Note that the withZone method correctly converts the date and time to my timezone (in America/Sao_Paulo the current offset is UTC-03:00), so it was adjusted accordingly.
If you want to get just the time (hour/minute/second), you can use toLocalTime() method:
System.out.println(mStartDate.withZone(DateTimeZone.getDefault()).toLocalTime()); // 21:00:00.000
The output is:
21:00:00.000
If you want another format (for example, don't print the 3 digits of fraction-of-second), you can use a DateTimeFormatter. The good thing is that you can set a timezone in the formatter, so you don't need to convert the DateTime:
// create formatter for hour/minute/second, set it with my default timezone
DateTimeFormatter fmt = DateTimeFormat.forPattern("HH:mm:ss").withZone(DateTimeZone.getDefault());
System.out.println(fmt.print(mStartDate)); // 21:00:00
The output is:
21:00:00
To get your range, you can use one of the methods above with your DateTime's (mStartDate and mEndDate), and use the DateTimeFormatter to change to whatever format you need.
PS: what I think you're missing when using getMillis() is that both datetimes (in UTC and in default timezone) represents the same instant. You are just converting this instant to a local time, but the millis is the same (think that, right now, at this moment, everybody in the world are in the same instant (the same millis), but their local times might be different depending on where they are). So, when converting a UTC DateTime to another timezone, we're just finding what is the local time in that zone, that corresponds to the same millis.
You can check this using the getMillis() method on both objects:
System.out.println(mStartDate.getMillis()); // 1497312000000
System.out.println(mStartDate.withZone(DateTimeZone.getDefault()).getMillis()); // 1497312000000
Note that, even if I convert the object to another timezone, the millis remains the same (1497312000000). That's because both represent the same instant, I'm just moving them to another timezone where the respective local time is different.
Java new Date/Time API
Joda-Time it's being discontinued and replaced by the new APIs, so I don't recommend start a new project with it. If that's your case, you can consider using the new Date/Time API, but if you have a big codebase using Joda or don't want to migrate it now, you can desconsider the rest of the answer.
Anyway, even in joda's website it says: "Note that Joda-Time is considered to be a largely “finished” project. No major enhancements are planned. If using Java SE 8, please migrate to java.time (JSR-310).".*
If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs. I'm not sure if it's already available to all Android versions (but see the alternative below).
If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's a way to use it, with the ThreeTenABP (more on how to use it here).
The code below works for both.
The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.
To get the current date at start of the day in UTC, you can do:
// UTC's today at start of the day
ZonedDateTime utc = LocalDate.now(ZoneOffset.UTC).atStartOfDay(ZoneOffset.UTC);
System.out.println(utc); // 2017-06-13T00:00Z
First I did LocalDate.now(ZoneOffset.UTC) to find the current local date in UTC. If I use just LocalDate.now(), it'll get the current date in my default timezone, which is not what we want (it might be different from UTC, depending on where - and when - you are and what the default timezone is).
Then I used atStartOfDay(ZoneOffset.UTC) to get the start of the day at UTC. I know it sounds redundant to use UTC twice, but the API allows us to use any timezone in this method, and IMO it makes explicit what timezone we want (if the date is in a timezone with Daylight Saving changes, the start of day might not be midnight - the timezone parameter is to guarantee that the correct value is set).
The output is:
2017-06-13T00:00Z
To convert to my default timezone, I can use ZoneId.systemDefault(), which in my case returns America/Sao_Paulo. To convert it and get only the local time part, just do:
System.out.println(utc.withZoneSameInstant(ZoneId.systemDefault()).toLocalTime()); // 21:00
The output is:
21:00
If you want to change it, you can also use a formatter:
// formatter for localtime (hour/minute/second)
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("HH:mm:ss");
System.out.println(fmt.format(utc.withZoneSameInstant(ZoneId.systemDefault()))); // 21:00:00
The output is:
21:00:00
java.time
The Joda-Time project is now in maintenance mode, with the project advising migration to the java.time classes.
Zones
Our server requires a start date and end date to be in UTC (which is probably obvious).
Yes, use UTC for much of your business logic, as well as for logging, storing, and exchanging date-time values. Think of UTC as the One True Time, with other zones being mere variations. Apply a time zone only when required for specific rules in your business logic or for presentation to the user.
For a value in UTC, use 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() ; // Capture the current moment in UTC.
To see the same moment in a particular time zone, assign a ZoneId to get a ZonedDateTime object. Same moment, same point on the timeline, different wall-clock time.
ZoneId zTunis = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdtTunis = instant.atZone( zTunis ) ;
See the same moment in yet another zone.
ZoneId zAuckland = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdtAuckland = instant.atZone( zAuckland );
Strings
So my question is how can I get a nicely formatted local date range with 2 UTC timestamps?
After making the adjustments from UTC to a time zone as shown above, generate strings to represent their value.
To generate a String representing any of those objects in standard ISO 8601 format, simply call toString.
String output = instant.toString() ;
2018-01-23T01:23:45.123456Z
String output = zdtAuckland.toString() :
2018-01-23T14:23:45.123456+13:00[Pacific/Auckland]
To generate a String in other formats, define a formatting pattern. Or 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, separators, and such.
Example:
Locale l = Locale.CANADA_FRENCH ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( l );
String output = zdt.format( f );
mardi 23 janvier 2018 à 14:23:45 heure avancée de la Nouvelle-Zélande
Note that time zone has nothing to do with Locale. One is for content, the other is for presentation.
Interval
When representing a pair of moments, a couple of start-stop moments, use the Interval class found in the ThreeTen-Extra library (linked below). This class represents a pair of Instant objects.
Its toString method generates a string is standard ISO 8601 format. For other formats, and for adjustments into other zones, use the code seen above to apply to each Instant a ZoneId to generate a ZonedDateTime. Access each Instant via getStart & getEnd.
Interval interval = Interval.of( start , stop ) ;
interval.toString(): 2007-12-03T10:15:30/2007-12-04T10:15:30
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.
Why does java.util.Date object show date & time with respect to a timezone when in actuality, java.util.Date represents an instant on the time-line, not a "date"?
The actual data stored within the object is a long count of milliseconds since 1970-01-01T00:00Z (midnight at the start of 1970 GMT/UTC).
Also in docs, A java.util.Date instance has no concept of time-zone.
If so is the case, why does this snippet print date specifying timezone.
public static void main(String[] args) {
Date date = new Date();
System.out.println(date);
}
Output : Wed Mar 22 14:58:56 IST 2017
Why is it showing specific timezone in the output? I understand the SOP implements toString() internally. Does toString() effect the timezone?
Just follow the javadoc, as it says:
public String toString()
Converts this Date object to a String of the form:
dow mon dd hh:mm:ss zzz yyyy
zzz is the time zone (and may reflect daylight saving time).
And when you dive into the source code, that this toString() implementation will at some point use TimeZone.getDefault()
( or to be precise: getDefaultRef()). In other words: the default implementation pulls in the "default" timezone of your JVM.
tl;dr
Current moment in UTC.
Instant.now() // Capture current moment in UTC.
.toString() // Generate String in standard ISO 8601 format.
2018-01-23T01:23:45.677340Z
Current moment in India time zone.
ZonedDateTime.now(
ZoneId.of( "Asia/Kolkata" )
).toString() // Generate string in format wisely extended from ISO 8601 standard, adding the time zone name in square brackets.
2018-01-23T06:53:45.677340+05:30[Asia/Kolkata]
Avoid legacy date-time classes
Why does java.util.Date object show date & time with respect to a timezone when in actuality, java.util.Date represents an instant on the time-line, not a "date"?
Because the java.util.Date and related classes (Calendar, SimpleDateFormat, and such) are poorly-designed. While a valiant effort at tackling the tricky subject of date-time handling, they fall short of the goal. They are riddled with poor design choices. You should avoid them, as they are now supplanted by the java.time classes, an enormous improvement.
Specifically to answer your question: The toString method of Date dynamically applies the JVM’s current default time zone while generating a String. So while the Date object itself represents a moment in UTC, the toString creates the false impression that it carries the displayed time zone.
Even worse, there is a time zone buried inside the Date object. That zone is used internally, yet is irrelevant to our discussion here. Confusing? Yes, yet another reason to avoid this class.
A java.util.Date instance has no concept of time-zone.
Not true. A Date represents a specific moment, a point on the timeline, with a resolution of milliseconds, in UTC. As you mention, it is defined as a count of milliseconds since the first moment of 1970 in UTC.
java.time
The java.time classes separate clearly the concepts of UTC, zoned, and unzoned values.
The java.time.Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction). This class replaces java.util.Date.
Instant instant = Instant.now() ; // Capture current moment in UTC.
Apply a time zone (ZoneId object) to an Instant and you get a ZonedDateTime object. That class replaces the java.util.Calendar class.
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = instant.atZone( z ) ; // Same simultaneous moment as `instant`, but different wall-clock time.
If a value has only an offset-from-UTC but not a full time zone, use the OffsetDateTime class.
For a date only, without time-of-day and without time zone, use the LocalDate class. This class replaces the java.sql.Date class. Ditto for LocalTime replacing java.sql.Time.
LocalDate xmasDate2018 = LocalDate.of( 2018 , Month.DECEMBER , 25 ) ;
If the zone or offset are unknown or indeterminate, such as "Christmas starts at stroke of midnight on December 25, 2018", use the LocalDateTime class. This class does not represent an actual moment, a specific point on the timeline. This class lacks any concept of time zone or offset. So it can only represent potential moments along a range of about 26-27 hours.
LocalDateTime xmasEverywhere2018 = LocalDateTime.of( xmasDate2018 , LocalTime.MIN ) ;
Or…
LocalDateTime xmasEverywhere2018 = LocalDateTime.of( 2018 , Month.DECEMBER , 25 , 0 , 0 , 0 , 0 ) ;
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.
With a JDBC driver complying with JDBC 4.2 or later, you may exchange java.time objects directly with your database. No need for strings or 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.
It does have a concept of time zone, but it is always UTC. When it prints the date therefore there is no problem converting it to the time zone of your computer.
I am making a change to some code which runs on a unix box. It sets the time for a field in a database based on the current date and time for London.
The methods I am using are as follows;
private static Date getCurrentTime() {
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd-kk:mm:ss.SSS");
format.setTimeZone(TimeZone.getTimeZone("Europe/London"));
Calendar cal = Calendar.getInstance();
Date currentDate = cal.getTime();
try {
return format.parse(format.format(currentDate));
} catch (ParseException e) {
log.error("Error occured while parsing date-->" + e.getMessage());
}
return new Date();
}
private String getStringFromDate(Date date){
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-kk:mm:ss.SSS");
return sdf.format(date);
}
When the message is processed by the java app on the production unix box (which is set to north america time as thats where it is hosted) then when it is inserted into the database it is an hour behind (not being set to BST).
If I run the same code in Eclipse on my desktop, I get the correct time in the database.
I am unsure what might be causing this issue and was hoping someone might be able to help.
Thanks
edit*** at second glance, even the log files on the unix box are an hour behind so on that basis i assume its unix that is causing the issue opposed to my code.
A Date instance is always in UTC (or, it should be unless you've done something wrong). you should store your dates in the db in UTC and convert them to whatever timezone you desire when presenting them to the user. anything else is just asking for trouble.
your code which formats and then parses the Date instance in the same TimeZone is just meaningless.
tl;dr
A Date (and Instant) are always in UTC by definition. So no need to futz with time zone.
Instant.now() // Capture current moment in UTC.
Or, if you must use the troublesome legacy class Date:
java.util.Date.from( Instant.now() ) // Avoid the legacy classes whenever possible. When required, you can convert back-and-forth via new methods added to the old classes as seen here.
Always specify time zone
Never rely on the current default time zone of either your host OS or your JVM. That default value is out of your control and can change at any moment during runtime.
Instead:
Always use the java.time classes rather than the troublesome old legacy classes seen in your code.
Always specify your desired/expected time zone as an optional argument to the various java.time methods rather than rely implicitly on the JVM’s current default.
java.time
You appear to be trying to get the current moment as a java.util.Date object. That legacy class represents a value in UTC, so the time zone is irrelevant.
Instant
The modern replacement for that class is java.time.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).
Capturing the current moment is simple: Instant.now.
Instant instant = Instant.now() ; // Capture the current moment in UTC.
If you must have Date to inter-operate with old code not yet updated to java.time, convert by calling new methods added to the old classes.
java.util.Date javaUtilDate = java.util.Date.from( instant ) ;
Either way, be very aware that both a Date and an Instant represent a point on the timeline in UTC, always UTC.
UTC versus London Time
Also, be aware that UTC is not London time, a common misconception given that UTC/GMT is tracked from a point at the Royal Observatory, Greenwich. Actually, London has a history of anomalies in its offset-from-UTC, including the adoption of Daylight Saving Time (DST).
To get London time, assign a ZoneId to get a ZonedDateTime.
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( "Europe/London" ) ;
ZonedDateTime zdt = instant.atZone( z ) ; // Same moment, same point on the timeline, but viewed with a different wall-clock time used by the people of a particular region (time zone).
Generally, best practice is to keep your servers in UTC, and to do as much of your business logic, storage, and exchange of date-time values in UTC. Use a zoned value such as London time only when required either by business logic or presentation to user.
Notice in the code seen above that the current default time zone of any computer or JVM is irrelevant. A change in that default has no effect on your code.
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 (<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.
I did:
GregorianCalendar gc = new GregorianCalendar(Locale.French);
And the hour is off by one hour. I get 14:17 instead of 15:17.
My first thought was DST, but I think gregoriancalendar takes that into account.
The time is set correctly on my pc.
The constructor you use is creating a Calendar with the default Timezone (javadoc), this might not be the timezone correct fpr the given locale. At leasst, thats how i read the javadoc. Try using a different constructor and pass your TZ in.
tl;dr
As noted in a comment, you confused using a Locale object with specifying a time zone. A locale has nothing to do with a time zone, and a locale does not affect the meaning of the date-time value. A locale affects only the formatting of a String used in presentation of the date-time value.
No locale needed when capturing the current moment. But we do need a time zone.
Instant.now().atZone( ZoneId.of( "America/Montreal" ) )
…or shorter version…
ZonedDateTime.now( ZoneId.of( "America/Montreal" ) )
java.time
You are using troublesome old legacy date-time classes, now supplanted by the java.time classes.
Work in UTC
Much of your business logic, data storage, and data exchange should be in UTC. Think of UTC as “the One True Time”.
The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds.
Instant instant = Instant.now();
Specify time zone
As you figured out, you should always specify the desired/expected time zone. For any given moment, the date and the time-of-day vary around the world by zone.
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( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
Specify locale
Be aware that time zone and locale are orthogonal, completely separate issues.
Time zone determines the meaning of the date-time, how we view its wall-clock time.
Locale determines (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.
This means we can mix-and-match any time zone with any locale. We can have a date-time in zone Europe/Paris with a locale of Locale.KOREA. Or a zone of Pacific/Auckland with Locale.CANADA_FRENCH.
So locale only impact presentation of the date-time, how we generate a String representation of the date-time.
You can specify a custom formatting pattern for generation of strings. But better to let java.time automatically localize.
Locale l = Locale.CANADA_FRENCH ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL )
.withLocale( l );
String output = zdt.format( f );
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, 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.
I am not sure what you are trying, but GregorianCalendar(Locale) is always based on your default time zone. -- Maybe you should have a look at GregorianCalendar(TimeZone zone, Locale aLocale)