I am new to Java's Date class. When I try to use its getTime() function for calculating time difference, issues come out. For example, below is the code.
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
task = opt.get();
task.setEndDate(dateFormat.format(date));
Date startDate = null;
try {
startDate = dateFormat.parse(task.getStartDate());
} catch (ParseException e) {
System.out.println("date parsing error...");
startDate = date;
}
System.out.printf("Start date is: %s", task.getStartDate());
System.out.printf("Start date is: %d", startDate.getTime());
System.out.printf("End date is: %s", task.getEndDate());
System.out.printf("End date is: %d", date.getTime());
long diff = date.getTime() - startDate.getTime() - 43200000;
System.out.printf("Time difference is: %d", diff);
int secNum = (int)(diff / 1000);
String timeCost = String.valueOf(secNum);
System.out.println("Time cost(sec) is:");
System.out.println(timeCost);
task.setTimeCost(timeCost);
The outputs are:
Start date is: 2020-04-15 01:46:17
Start date is: 1586929577000
End date is: 2020-04-15 01:46:35
End date is: 1586972795461
Time difference is: 18461
Time cost(sec) is:18
As you might notice, there is 12 hours(43200000 ms) offset between the calculated difference and the real difference through "date.getTime() - startDate.getTime()".
I don't know what's going on.
Does anyone have an idea and correct me ?
It seems you are storing the date/time as a string in your task object, and converting between Date and String using the format "yyyy-MM-dd hh:mm:ss". I believe lower-case h means you are using a 12-hour clock, but you do not include an AM/PM indicator in your format string.
I'm guessing you ran the code at 1:46 PM to produce the sample output.
You have "2020-04-15 01:46:17" stored as your start date. When you convert that back to a date, the formatter doesn't know whether it is an AM time or PM time. I guess that it defaults to AM.
The Date object, however, knows that it was initialized with a PM time. Therefore, when you subtract the two, you get over 12 hours difference, because it is subtracting 1:46:17 AM from 1:46:35 PM.
A simple recommendation would be to add an AM/PM indicator to your date format, or use a 24-hour clock (upper-case H in the format string).
An even better recommendation would be to store dates as dates, not as strings! Convert them to strings when you want to display them.
You are using hh which is a 12-hour hour format, hence 20:00 becomes 08:00. You should use HH which is a 24-hour format. The below illustrates the difference.
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
Date date = new Date(1586973600000L);
System.out.println(date);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String fd1 = df.format(date);
System.out.println(fd1);
System.out.println(df.parse(fd1));
df.applyPattern("yyyy-MM-dd HH:mm:ss");
String fd2 = df.format(date);
System.out.println(fd2);
System.out.println(df.parse(fd2));
Also, java.util.Date is old, buggy and generally avoided for some time now. You might want to switch to java.time instead.
java.time
I am new to Java's Date class.
Stop! Backup, rewind.
Both java.util.Date and java.sql.Date classes are terrible, deeply flawed, and quite frustrating. Never use these classes.
These classes were shipped in the earliest versions of Java. Supplanted years ago by the modern java.time classes defined in JSR 310.
Date date = new Date();
To capture the current moment in UTC, use Instant.now. Uses a resolution finer than the milliseconds used in the java.util.Date class it replaced.
Instant instant = Instant.now() ; // Capture the current moment in UTC.
task.setEndDate(dateFormat.format(date));
Your Task class should hold a java.time object rather than a mere string.
class Task {
Instant start , stop ;
…
}
Use smart objects rather than dumb strings throughout your Java codebase. Doing so ensures valid values, provides type-safety, and makes your code more self-documenting.
If your Task is like booking appointments in the future, where you want a certain time-of-day regardless of changes to the offset used by your time zone, then use LocalDateTime. This type represents only a date and time-of-day but lacks any concept of time zone or offset.
LocalDate ld = LocalDate.of( 2020 , Month.APRIL , 15 ) ;
Localtime lt = LocalTime.of( 15 , 30 ) ;
LocalDateTime ldt = LocalDateTime.of( ld , lt ) ;
When generating a calendar where you need a specific point on the timeline, then apply the relevant time zone.
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;
The issue at stake here is the fact that politicians around the world have shown a predilection for changing the offset used by the time zone(s) of their jurisdiction. The politicians do so with surprising frequency. And they have done so with little or no forewarning.
When exchanging date-time values with other systems textually, then use ISO 8601 formats. These formats are used by default in java.time when parsing/generating text. And for presentation to users, produce automatically localized strings using DateTimeFormatter.
new SimpleDateFormat("yyyy-MM-dd hh:mm:ss")
This format is incorrect if you are trying to record moments, specific points on the timeline. You must include an indication of time zone and/or offset-from-UTC to track a moment.
For moments, use the ISO 8601 formats mentioned above. Used by default, so no need to specify a formatting pattern.
String input = "2020-01-23T01:23:45.123456789Z" ;
Instant instant = Instant.parse( input ) ;
Adjust from UTC into the wall-clock time used by the people of a particular region (a time zone).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
Generate localized text.
Locale locale = Locale.CANADA_FRENCH ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( locale ) ;
String output = zdt.format( f ) ;
See this code run live at IdeOne.com.
zdt.toString(): 2020-01-22T20:23:45.123456789-05:00[America/Montreal]
output: mercredi 22 janvier 2020 à 20 h 23 min 45 s heure normale de l’Est
long diff = date.getTime() - startDate.getTime() - 43200000;
No need to do the math yourself. We have a class for that: Duration.
Duration d = Duration.between( start , stop ) ;
If you want a count of whole seconds across the entire span of time, call Duration::toSeconds.
long seconds = d.toSeconds() ; // Entire duration in terms of whole seconds.
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. Hibernate 5 & JPA 2.2 support java.time.
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.
Related
I wanted to convert a date from one time zone to another, using SimpleDateFormat class in java. But somehow it is generating different results which are suppose to be in the same TimeZone.
Here is a test case, and its generating one result as IST and other one as GMT. i think it should be generating only GMT's for both cases.
public class TestOneCoreJava {
public static void main(String[] args) throws ParseException {// Asia/Calcutta
DateFormat formatter = new SimpleDateFormat("dd-MMM-yy hh:mm:ss a");
System.out.println(getDateStringToShow(formatter.parse("26-Nov-10 03:31:20 PM +0530"),"Asia/Calcutta", "Europe/Dublin", false));
System.out.println(getDateStringToShow(formatter.parse("02-Oct-10 10:00:00 AM +0530"),"Asia/Calcutta", "Europe/Dublin", false));
//------Output--
//26-Nov-10 GMT
//02-Oct-10 IST
}
public static String getDateStringToShow(Date date,
String sourceTimeZoneId, String targetTimeZoneId, boolean includeTime) {
String result = null;
// System.out.println("CHANGING TIMEZONE:1 "+UnitedLexConstants.SIMPLE_FORMAT.format(date));
String date1 = new SimpleDateFormat("dd-MMM-yy hh:mm:ss a").format(date);
SimpleDateFormat sourceTimeZoneFormat = new SimpleDateFormat("Z");
sourceTimeZoneFormat.setTimeZone(TimeZone.getTimeZone(sourceTimeZoneId));
date1 += " " + sourceTimeZoneFormat.format(date);
// Changed from 'Z' to 'z' to show IST etc, in place of +5:30 etc.
SimpleDateFormat targetTimeZoneFormat = new SimpleDateFormat("dd-MMM-yy hh:mm:ss a z");
targetTimeZoneFormat.setTimeZone(TimeZone.getTimeZone(targetTimeZoneId));
SimpleDateFormat timeZoneDayFormat = null;
if (includeTime) {
timeZoneDayFormat = targetTimeZoneFormat;
} else {
timeZoneDayFormat = new SimpleDateFormat("dd-MMM-yy z");
}
timeZoneDayFormat.setTimeZone(TimeZone.getTimeZone(targetTimeZoneId));
try {
result = timeZoneDayFormat.format(targetTimeZoneFormat.parse(date1));
// System.out.println("CHANGING TIMEZONE:3 "+result);
} catch (ParseException e) {
e.printStackTrace();
}
return result;
}
}
tl;dr
Use modern java.time classes, specifically ZonedDateTime and ZoneId. See Oracle Tutorial.
ZonedDateTime // Represent a date and time-of-day in a specific time zone.
.now( // Capture the current moment as seen in the wall-clock time used by the people of a particular region (a time zone).
ZoneId.of( "Pacific/Auckland" ) // Specify time zone using proper name in `Continent/Region` format. Never use 3-4 letter pseudo-zone such as IST or PST or EST.
) // Returns a `ZonedDateTime` object.
.withZoneSameInstant( // Adjust from one time zone to another. Same point on the timeline, same moment, but different wall-clock time.
ZoneId.of( "Africa/Tunis" )
) // Returns a new fresh `ZonedDateTime` object rather than altering/“mutating” the original, per immutable objects pattern.
.toString() // Generate text in standard ISO 8601 format, extended to append name of zone in square brackets.
2018-09-18T21:47:32.035960+01:00[Africa/Tunis]
For UTC, call ZonedDateTime::toInstant.
Avoid 3-Letter Time Zone Codes
Avoid those three-letter time zone codes. They are neither standardized nor unique. For example, your use of "IST" may mean India Standard Time, Irish Standard Time, and maybe others.
Use proper time zone names. The definition of time zones and their names change frequently, so keep your source up-to-date. For example the old "Asia/Calcutta" is now "Asia/Kolkata". And not just names; governments are notorious for changing the rules/behavior of a time zone, occasionally at the last minute.
Avoid j.u.Date
Avoid using the bundled java.util.Date and Calendar classes. They are notoriously troublesome and will be supplanted in Java 8 by the new java.time.* package (which was inspired by Joda-Time).
java.time
Instant
Learn to think and work in UTC rather than your own parochial time zone. Logging, data-exchange, and data-storage should usually be done in UTC.
Instant instant = Instant.now() ; // Capture the current moment in UTC.
instant.toString(): 2018-09-18T20:48:43.354953Z
ZonedDateTime
Adjust into a time zone. Same moment, same point on the timeline, different wall-clock time. Apply a ZoneId (time zone) to get a ZonedDateTime object.
ZoneId zMontreal = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdtMontreal = instant.atZone( zMontreal ) ; // Same moment, different wall-clock time.
We can adjust again, using either the Instant or the ZonedDateTime.
ZoneId zKolkata = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdtKolkata = zdtMontreal.withZoneSameInstant( zKolkata ) ;
ISO 8601
Calling toString on any of these classes produce text in standard ISO 8601 class. The ZonedDateTime class extends the standard wisely by appending the name of the time zone in square brackets.
When exchanging date-time values as text, always use ISO 8601 formats. Do not use custom formats or localized formats as seen in your Question.
The java.time classes use the standard formats by default for both parsing and generating strings.
Instant instant = Instant.parse( "2018-01-23T01:23:45.123456Z" ) ;
Using standard formats avoids all that messy string manipulation seen in the Question.
Adjust to UTC
You can always take a ZonedDateTime back to UTC by extracting a Instant.
Instant instant = zdtKolkata.toInstant() ;
DateTimeFormatter
To represent your date-time value in other formats, search Stack Overflow for DateTimeFormatter class. You will find many examples and discussions.
UPDATE: The Joda-Time project is now in maintenance-mode, and advises migration to the java.time classes. I am leaving this section intact as history.
Joda-Time
Beware of java.util.Date objects that seem like they have a time zone but in fact do not. In Joda-Time, a DateTime does indeed know its assigned time zone. Generally should specify a desired time zone. Otherwise, the JVM's default time zone will be assigned.
Joda-Time uses mainly immutable objects. Rather than modify an instance, a new fresh instance is created. When calling methods such as toDateTime, a new fresh DateTime instance is returned leaving the original object intact and unchanged.
//DateTime now = new DateTime(); // Default time zone automatically assigned.
// Convert a java.util.Date to Joda-Time.
java.util.Date date = new java.util.Date();
DateTime now = new DateTime( date ); // Default time zone automatically assigned.
DateTimeZone timeZone = DateTimeZone.forID( "Asia/Kolkata" );
DateTime nowIndia = now.toDateTime( timeZone );
// For UTC/GMT, use built-in constant.
DateTime nowUtcGmt = nowIndia.toDateTime( DateTimeZone.UTC );
// Convert from Joda-Time to java.util.Date.
java.util.Date date2 = nowIndia.toDate();
Dump to console…
System.out.println( "date: " + date );
System.out.println( "now: " + now );
System.out.println( "nowIndia: " + nowIndia );
System.out.println( "nowUtcGmt: " + nowUtcGmt );
System.out.println( "date2: " + date2 );
When run…
date: Sat Jan 25 16:52:28 PST 2014
now: 2014-01-25T16:52:28.003-08:00
nowIndia: 2014-01-26T06:22:28.003+05:30
nowUtcGmt: 2014-01-26T00:52:28.003Z
date2: Sat Jan 25 16:52:28 PST 2014
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.
When dealing with Timezone issues in Google API. I came across such kind of issues.
Look at this piece of code of yours:-
System.out.println(getDateStringToShow(formatter.parse("26-Nov-10 03:31:20 PM
+0530"),"Asia/Calcutta", "Europe/Dublin", false));
System.out.println(getDateStringToShow(formatter.parse("02-Nov-10 10:00:00 AM
+0530"),"Asia/Calcutta", "Europe/Dublin", false));
If i give above as input it will run fine the way we want to.
If you still want to go with this way then you have to perform calculation according to your need.
Like adjusting the time Mathematically and things similar to it.
Or a Simple fix for your case will be something like this
SimpleDateFormat d =new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
d.setTimeZone(TimeZone.getTimeZone("Europe/Dublin"));
Date firsttime = d.parse("2013-12-19T03:31:20");
Date seondtime = d.parse("2013-12-19T10:00:00");
System.out.println(getDateStringToShow(firsttime,"Asia/Calcutta",
"Europe/Dublin", false));
System.out.println(getDateStringToShow(seondtime,"Asia/Calcutta",
"Europe/Dublin", false));
My suggestion will be to refer JODA API . More preferrable over Old School Date.
I found this funny behavior while using Date and Calendar class to handle Exponential distributions for simulating arrival time at a store (academic work). The code is quite simple and is below displayed. Well suppose that "this.currentDate" is "Feb 15 08:00:00 BRST 2014".
If i shift forward the time 24h (parameter iSeconds=86.400), what is supposed to return ? The expected string would be "2014-02-16 08:00:00" but instead the time is shortened in 1h and the result is "2014-02-16 07:00:00", I wonder if someone could explain why my one hour was "stolen". No big deal, but since my next arrival time depends of the earlier one, it makes a mess over my time baseline shifting all of them one hour as well.
I thought could be some TZ issue, but heck, i just moved 24h in the middle of February.
public String shiftTimeStamp( int iSeconds)
{
Calendar cal = Calendar.getInstance();
cal.setTime(this.currentDate);
cal.add(Calendar.SECOND, iSeconds);
this.currentDate = cal.getTime();
String sTS = new SimpleDateFormat(SCSimLabels.DATE_TS_FORMAT).format(this.currentDate);
return sTS;
}
Note: Daylight Saving Time issue :) BRT <--> BRST tz.
my workaround: I just want a beacon to guide the time jumps caused by inter arrival times and I´m not interested on such calendar specificities, so when I need to move to the first work hour of the next day I just force the time to be 08:00:00 after 1 day shift. It works like a charm :)
Calendar cal = Calendar.getInstance();
cal.setTime(this.currentDate);
cal.add(Calendar.DATE, 1);
String sDate = (new SimpleDateFormat("yyyy-MM-dd 08:00:00")).format(cal.getTime());
Date newDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(sDate);
this.currentDate = newDate;
Change the format call to this:
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z").format(this.currentDate);
To see what timezone the format call is using. I bet the call to .add() is modifying the Calendar object's timezone since it crosses the standard time / daylight time border.
If this is the case, you could try adding a Calendar.DAY,1 or simply .setTimeZone(...) of the Calendar obj. back to the original timezone after the .add call.
Avoid legacy date-time classes
You are using troublesome old date-time classes that are now legacy, supplanted by the java.time classes.
Using java.time
If you want to work with generic 24-hour days without any time zone or offset-from-UTC, use the LocalDateTime class. If you always want to start at 8 AM, specify a LocalTime.
LocalDate ld = LocalDate.of( 2014 , Month.FEBRUARY , 15 ) ;
LocalTime lt = LocalTime.of( 8 , 0 ) ; // Specify hour in 24-hour clock, 0-23.
LocalDateTime ldt = LocalDateTime.of( ld , lt );
Represent your 24 hour span as a Duration.
Duration d = Duration.ofHours( 24 );
LocalDateTime ldtLater = ldt.plus( d );
If you want to work with specific moments on the timeline as seen through the lens of a region’s particular wall-clock time, then specify a ZoneId to get a ZonedDateTime.
ZoneId z = ZoneId.of( "America/Sao_Paulo" ) ;
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;
ZonedDateTime zdtLater = zdt.plus( d );
Note that adding 24 hours to a ZonedDateTime is not the same thing as adding a day. As you have learned the hard way, anomalies such as Daylight Saving Time (DST) means a day may be 23, 24, or 25 hours long, or even other lengths. So if you want to add a day and let java.time apply its logic to arrive at an appropriate time-of-day while taking into consideration anomalies such as DST, add days rather than hours.
ZonedDateTime zdtLater = zdt.plusDays( 1 );
Or add a Period of one whole day rather than a Duration of 24 hours.
Period p = Period.ofDays( 1 );
ZonedDateTime zdtLater = zdt.plus( p );
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
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
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 have a String of a date and time like this: 2011-04-15T20:08:18Z. I don't know much about date/time formats, but I think, and correct me if I'm wrong, that's its UTC format.
My question: what's the easiest way to parse this to a more normal format, in Java?
tl;dr
String output =
Instant.parse ( "2011-04-15T20:08:18Z" )
.atZone ( ZoneId.of ( "America/Montreal" ) )
.format (
DateTimeFormatter.ofLocalizedDateTime ( FormatStyle.FULL )
.withLocale ( Locale.CANADA_FRENCH )
)
;
vendredi 15 avril 2011 16 h 08 EDT
Details
The answer by Josh Pinter is correct, but could be even simpler.
java.time
In Java 8 and later, the bundled java.util.Date/Calendar classes are supplanted by the java.time framework defined by JSR 310. Those classes are inspired by Joda-Time but are entirely re-architected.
The java.time framework is the official successor to Joda-Time. The creators of Joda-Time have advised we should migrate to java.time as soon as is convenient. Joda-Time continues to be updated and tweaked, but further innovation will be done only in java.time and its extensions in the ThreeTen-Extra project.
The bulk of java.time functionality has been back-ported to Java 6 & 7 in the ThreeTen-Backport project, and further adapted to Android in ThreeTenABP project.
The equivalent for the Joda-Time code above is quite similar. Concepts are similar. And like Joda-Time, the java.time classes by default use ISO 8601 formats when parsing/generating textual representations of date-time values.
An Instant is a moment on the timeline in UTC with a resolution of nanoseconds (versus milliseconds used by Joda-Time & java.util.Date).
Instant instant = Instant.parse( "2011-04-15T20:08:18Z" );
Apply a time zone (ZoneId) to get a ZonedDateTime.
ZoneId zoneId = ZoneId.of( "Asia/Kolkata" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
Adjust into yet another time zone.
ZoneId zoneId_NewYork = ZoneId.of( "America/New_York" );
ZonedDateTime zdt_NewYork = zdt.withZoneSameInstant( zoneId_NewYork );
To create strings in other formats beyond those of the toString methods, use the java.time.format classes. You can specify your own formatting pattern or let java.time localize automatically. Specify a Locale for (a) the human language used in translation of name of month/day-of-week, and (b) cultural norms for period-versus-comma, order of the parts, and such.
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL );
formatter = formatter.withLocale( Locale.US );
String output = zdt_NewYork.format( formatter );
Friday, April 15, 2011 4:08:18 PM EDT
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.
Joda-Time
UPDATE: The Joda-Time project is now in maintenance mode, with the team advising migration to the java.time classes. This section left intact for history.
Pass String To Constructor
Joda-Time can take that string directly. Simply pass to a constructor on the DateTime class.
Joda-Time understands the standard ISO 8601 format of date-times, and uses that format as its default.
Example Code
Here is example code in Joda-Time 2.3 running in Java 7 on a Mac.
I show how to pass the string to a DateTime constructor, in two ways: With and without a time zone. Specifying a time zone solves many problems people encounter in doing date-time work. If left unspecified, you get the default time zone which can bring surprises when placed into production.
I also show how specify no time zone offset (UTC/GMT) using the built-in constant DateTimeZone.UTC. That's what the Z on the end, short for Zulu time, means: No time zone offset (00:00).
// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// import org.joda.time.*;
// import org.joda.time.format.*;
// Default time zone.
DateTime dateTime = new DateTime( "2011-04-15T20:08:18Z" );
// Specified time zone.
DateTime dateTimeInKolkata = new DateTime( "2011-04-15T20:08:18Z", DateTimeZone.forID( "Asia/Kolkata" ) );
DateTime dateTimeInNewYork = new DateTime( "2011-04-15T20:08:18Z", DateTimeZone.forID( "America/New_York" ) );
// In UTC/GMT (no time zone offset).
DateTime dateTimeUtc = dateTimeInKolkata.toDateTime( DateTimeZone.UTC );
// Output in localized format.
DateTimeFormatter formatter = DateTimeFormat.shortDateTime().withLocale( Locale.US );
String output_US = formatter.print( dateTimeInNewYork );
Dump to console…
System.out.println("dateTime: " + dateTime );
System.out.println("dateTimeInKolkata: " + dateTimeInKolkata );
System.out.println("dateTimeInNewYork: " + dateTimeInNewYork );
System.out.println("dateTimeUtc: " + dateTimeUtc );
System.out.println("dateTime in US format: " + output_US );
When run…
dateTime: 2011-04-15T13:08:18.000-07:00
dateTimeInKolkata: 2011-04-16T01:38:18.000+05:30
dateTimeInNewYork: 2011-04-15T16:08:18.000-04:00
dateTimeUtc: 2011-04-15T20:08:18.000Z
dateTime in US format: 4/15/11 4:08 PM
Use JodaTime
I kept getting parsing errors using the other solutions with the Z at the end of the format.
Instead, I opted to leverage JodaTime's excellent parsing functionality and was able to do the following very easily:
String timestamp = "2011-04-15T20:08:18Z";
DateTime dateTime = ISODateTimeFormat.dateTimeParser().parseDateTime(timestamp);
This correctly recognizes the UTC timezone and allows you to then use JodaTime's extensive manipulation methods to get what you want out of it.
Hope this helps others.
Already has lot of answer but just wanted to update with java 8 in case any one faced issues while parsing string date.
Generally we face two problems with dates
Parsing String to Date
Display Date in desired string format
DateTimeFormatter class in Java 8 can be used for both of these purpose.
Below methods try to provide solution to these issues.
Method 1:
Convert your UTC string to Instant. Using Instant you can create Date for any time-zone by providing time-zone string and use DateTimeFormatter to format date for display as you wish.
String dateString = "2016-07-13T18:08:50.118Z";
String tz = "America/Mexico_City";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MMM d yyyy hh:mm a");
ZoneId zoneId = ZoneId.of(tz);
Instant instant = Instant.parse(dateString);
ZonedDateTime dateTimeInTz =ZonedDateTime.ofInstant(instant, zoneId);
System.out.println(dateTimeInTz.format(dtf));
Method 2:
Use DateTimeFormatter built in constants e.g ISO_INSTANT to parse string to LocalDate.
ISO_INSTANT can parse dates of pattern
yyyy-MM-dd'T'HH:mm:ssX e.g '2011-12-03T10:15:30Z'
LocalDate parsedDate
= LocalDate.parse(dateString, DateTimeFormatter.ISO_INSTANT);
DateTimeFormatter displayFormatter = DateTimeFormatter.ofPattern("yyyy MM dd");
System.out.println(parsedDate.format(displayFormatter));
Method 3:
If your date string has much precision of time e.g it captures fraction of seconds as well as in this case 2016-07-13T18:08:50.118Z then method 1 will work but method 2 will not work. If you try to parse it will throw DateTimeException Since ISO_INSTANT formatter will not be able to parse fraction of seconds as you can see from its pattern.
In this case you will have to create a custom DateTimeFormatter by providing date pattern as below.
LocalDate localDate
= LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX"));
Taken from a blog link written by me.
The Java 7 version of SimpleDateFormat supports ISO-8601 time zones using the uppercase letter X.
String string = "2011-04-15T20:08:18Z";
DateFormat iso8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
Date date = iso8601.parse(string);
If you're stuck with Java 6 or earlier, the answer recommending JodaTime is a safe bet.
You have to give the following format:
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
Date parse = simpleDateFormat.parse( "2011-04-15T20:08:18Z" );
I had a parse error in Andrew White solution.
Adding the single quote around the Z solved the issue
DateFormat m_ISO8601Local = new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ss'Z'");
the pattern in #khmarbaise answer worked for me, here's the utility method I extracted (note that the Z is omitted from the pattern string):
/**
* Converts an ISO-8601 formatted UTC timestamp.
*
* #return The parsed {#link Date}, or null.
*/
#Nullable
public static Date fromIsoUtcString(String isoUtcString) {
DateFormat isoUtcFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault());
isoUtcFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
try {
return isoUtcFormat.parse(isoUtcString);
} catch (ParseException e) {
e.printStackTrace();
return null;
}
}
For all the older versions of JDK (6 down) it may be useful.
Getting rid of trailing 'Z' and replacing it literally with 'UTC' timezone display name - then parsing the whole string using proper simple date formatter.
String timeZuluVal = "2011-04-15T20:08:18Z";
timeZuluVal = timeZuluVal.substring( 0, timeZuluVal.length() - 2 ); // strip 'Z';
timeZuluVal += " " + TimeZone.getTimeZone( "UTC" ).getDisplayName();
DateFormat simpleDateFormat = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss zzzz" );
Date dateVal = simpleDateFormat.parse( timeZuluVal );
Joda Time
public static final String SERVER_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
public static DateTime getDateTimeFromUTC(String time) {
try {
DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(SERVER_TIME_FORMAT).withZoneUTC();
Calendar localTime = Calendar.getInstance();
DateTimeZone currentTimeZone = DateTimeZone.forTimeZone(localTime.getTimeZone());
return dateTimeFormatter.parseDateTime(time).toDateTime().withZone(currentTimeZone);
} catch (Exception e) {
return DateTime.now();
}
}
I declared Calendar and SimpleDateFormat like this:
calendar = Calendar.getInstance(TimeZone.getTimeZone("Malaysia"));
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MMMMM.dd hh:mm aaa");
or:
calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+08:00"));
Then I call this:
sdf.format(calendar.getTime());
but result is not in correct time zone (+8 hours). What could be the problem?
Unless you are going to perform Date/Time related calculations, there is no point in instantiating Calendar with given TimeZone. After calling Calendar's getTime() method, you will receive Date object, which is timezone-less either way (GMT based, actually).
What you need to do, is to set TimeZone for formatter instead. And also do not bother with passing your own format, there is a built-in already:
// get current time
// you could just as well use Date now = new Date();
Calendar now = Calendar.getInstance();
// Locale for formatter
Locale malaysianLocale = new Locale("ms", "MY");
// Default date and time format for Malaysia
DateFormat defaultMalaysianFormatter = DateFormat.getDateTimeInstance(
DateFormat.DEFAULT, DateFormat.DEFAULT, malaysianLocale);
// This step is crucial
TimeZone malaysianTimeZone = TimeZone.getTimeZone("Asia/Kuala_Lumpur");
defaultMalaysianFormatter.setTimeZone(malaysianTimeZone);
System.out.println(defaultMalaysianFormatter.format(now.getTime()));
This prints something like 10 Mei 2011 2:30:05 AM, which I believe is your desired result.
Time zone id should be set as Asia/Kuala_Lumpur. Date.toString() always returns time string using default time zone. But your default time zone is different.
Calendar tzCal = Calendar.getInstance(TimeZone.getTimeZone("Asia/Kuala_Lumpur"));
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, tzCal.get(Calendar.YEAR));
cal.set(Calendar.MONTH, tzCal.get(Calendar.MONTH));
cal.set(Calendar.DAY_OF_MONTH, tzCal.get(Calendar.DAY_OF_MONTH));
cal.set(Calendar.HOUR_OF_DAY, tzCal.get(Calendar.HOUR_OF_DAY));
cal.set(Calendar.MINUTE, tzCal.get(Calendar.MINUTE));
cal.set(Calendar.SECOND, tzCal.get(Calendar.SECOND));
cal.set(Calendar.MILLISECOND, tzCal.get(Calendar.MILLISECOND));
System.out.println("Current Time = " + sdf.format(cal.getTime()));
The TimeZone.getTimeZone() call is incorrect. You have to pass a the correct identifier.
EDIT -- You can try to getAvailableIDs() and iterate through them to make sure you have the correct id.
If you've read the javadoc of TimeZone carefully, the way to use getTimeZone is:
TimeZone.getTimeZone("GMT-8")
or
TimeZone.getTimeZone("GMT+8")
tl;dr
java.time.ZonedDateTime.now(
ZoneId.of( "Asia/Kuala_Lumpur" )
).toString()
2018-01-23T18:48:32.263+08:00[Asia/Kuala_Lumpur]
Avoid legacy classes
The Question and other Answers use troublesome old date-time classes that are now legacy, supplanted by the java.time classes.
java.time
The modern approach uses java.time classes. Forget all about the terribly confusing Calendar class.
Current moment
First get the current moment in UTC. 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() ;
Time zone
Adjust into another 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 pseudo-zones such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "Asia/Kuala_Lumpur" ) ; // Or "Asia/Kuching", etc.
Apply the ZoneId to instantiate a ZonedDateTime object. Both the ZonedDateTime and Instant represent the same moment, the very same point on the timeline, but is viewed through a different wall-clock time.
ZonedDateTime zdt = instant.atZone( z ) ; // Same moment, different wall-clock time.
Offset
If you had only an offset-from-UTC such as +08:00 rather than a known time zone, you would use ZoneOffset to get a OffsetDateTime instead of a ZoneId & ZonedDateTime. But a time zone is always preferable to a mere offset. A zone is a history of offsets used by the people of particular region.
Strings
To generate a string in standard ISO 8601 format, call toString method.
The ZonedDateTime class wisely extends the standard by appending the time zone name in square brackets.
String output = zdt.toString() ; // YYYY-MM-DDTHH:MM:SS.SSSSSSSSS[tz]
Localize to the user’s preferences. 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.
Locale l = Locale.CANADA_FRENCH ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( l );
String output = zdt.format( f );
Dump to console.
System.out.println( "instant.toString(): " + instant ) ;
System.out.println( "output: " + output ) ;
System.out.println( "outputLocalized (always Locale.US on IdeOne.com): " + outputLocalized ) ;
See this code run live at IdeOne.com. Note that IdeOne.com overrides any Locale setting to always use Locale.US.
instant.toString(): 2018-01-23T10:48:32.263Z
output: 2018-01-23T18:48:32.263+08:00[Asia/Kuala_Lumpur]
ooutputLocalized (always Locale.US on IdeOne.com): Tuesday, January 23, 2018 6:48:32 PM MYT
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.
Can't understand why the following takes place:
String date = "06-04-2007 07:05";
SimpleDateFormat fmt = new SimpleDateFormat("MM-dd-yyyy HH:mm");
Date myDate = fmt.parse(date);
System.out.println(myDate); //Mon Jun 04 07:05:00 EDT 2007
long timestamp = myDate.getTime();
System.out.println(timestamp); //1180955100000 -- where are the milliseconds?
// on the other hand...
myDate = new Date();
System.out.println(myDate); //Tue Sep 16 13:02:44 EDT 2008
timestamp = myDate.getTime();
System.out.println(timestamp); //1221584564703 -- why, oh, why?
What milliseconds? You are providing only minutes information in the first example, whereas your second example grabs current date from the system with milliseconds, what is it you're looking for?
String date = "06-04-2007 07:05:00.999";
SimpleDateFormat fmt = new SimpleDateFormat("MM-dd-yyyy HH:mm:ss.S");
Date myDate = fmt.parse(date);
System.out.println(myDate);
long timestamp = myDate.getTime();
System.out.println(timestamp);
Because simple date format you specified discards the milliseconds. So the resulting Date object does not have that info. So when you print it out, its all 0s.
On the other hand, the Date object does retain the milliseconds when you assign it a value with milliseconds (in this case, using new Date()). So when you print them out, it contains the millisecs too.
Instead of using the Sun JDK Time/Date libraries (which leave much to be desired) I recommend taking a look at http://joda-time.sourceforge.net.
This is a very mature and active sourceforge project and has a very elegant API.
tl;dr
The accepted Answer by Vinko Vrsalovic is correct. Your input is whole minutes, so the milliseconds for fractional second should indeed be zero.
Use java.time.
LocalDateTime.parse
(
"06-04-2007 07:05" ,
DateTimeFormatter.ofPattern( "MM-dd-uuuu HH:mm" )
)
.atZone
(
ZoneId.of( "Africa/Casablanca" )
)
.toInstant()
.getEpochMilli()
java.time
The modern approach uses the java.time classes defined in JSR 310 that years ago supplanted the terrible classes you are using.
Define a formatting pattern to match your input. FYI: Learn to use standard ISO 8601 formats for exchanging date-time values as text.
String input = "06-04-2007 07:05" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "MM-dd-uuuu HH:mm" ) ;
Parse your input as a LocalDateTime, as it lacks an indicator of time zone or offset-from-UTC.
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;
This represents a date and a time-of-day, but lacks the context of a time zone or offset. So we do not know if you meant 7 AM in Tokyo Japan, 7 AM in Toulouse France, or 7 AM in Toledo Ohio US. This issue of time zone is crucial, because your desired count of milliseconds is a count since the first moment of 1970 as seen in UTC (an offset of zero hours-minutes-seconds), 1970-01-01T00:00Z.
So we must place your input value, the LocalDateTime object, in the context of a time zone or offset.
If your input was intended to represent a date and time in UTC, use OffsetDateTime with ZoneOffset.UTC.
OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC ) ; // Do this if your date and time represent a moment as seen in UTC.
If your input was intended to represent a date and time as seen through the wall-clock time used by the people of a particular region, use ZonedDateTime.
ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;
Next we want to interrogate for the count of milliseconds since the epoch of first moment of 1970 in UTC. With either a OffsetDateTime or ZonedDateTime object in hand, extract a Instant by calling toInstant.
Instant instant = odt.toInstant() ;
…or…
Instant instant = zdt.toInstant() ;
Now get count of milliseconds.
long millisecondsSinceEpoch = instant.toEpochMilli() ;
By the way, I suggest you not track time by a count of milliseconds. Use ISO 8601 formatted text instead: easy to parse by machine, easy to read by humans across cultures. A count of milliseconds is neither.
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. Hibernate 5 & JPA 2.2 support java.time.
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….
When you parse a date it only uses the information you provide.
In this case it only knows MM-dd-yyyy HH:mm.
Creating a new date object returns the current system date/time (number of milliseconds since the epoch).
toString() of a Date object does not show you the milliseconds... But they are there
So new Date() is an object with milisecond resolution, as can be seen by:
System.out.printf( "ms = %d\n", myDate.getTime() % 1000 ) ;
However, when you construct your date with SimpleDateFormat, no milliseconds are passed to it
Am I missing the question here?
[edit] Hahaha...way too slow ;)
Date.getTime returns the number of milliseconds since January 1, 1970, 00:00:00 GMT represented by the Date object. So "06-04-2007 07:05" - "01-01-1970 00:00" is equal to 1180955340000 milliseconds. Since the only concern of your question is about the time portion of the date, a rough way of thinking of this calculation is the number of milliseconds between 07:05 and 00:00 which is 25500000. This is evenly divisible by 1000 since neither time has any milliseconds.
In the second date it uses the current time when that line of code is executed. That will use whatever the current milliseconds past the current second are in the calculation. Therefore, Date.getTime will more than likely return a number that is not evenly divisible by 1000.
The getTime() method of Date returns the number of milliseconds since January 1, 1970 (this date is called the "epoch" because all computer dates are based off of this date). It should not be used to display a human-readable version of your Date.
Use the SimpleDateFormat.format() method instead. Here is a revised version of part of your code that I think may solve your problem:
String date = "06-04-2007 07:05:23:123";
SimpleDateFormat fmt = new SimpleDateFormat("MM-dd-yyyy HH:mm:ss:S");
Date myDate = fmt.parse(date);
System.out.println(myDate); //Mon Jun 04 07:05:23 EDT 2007
String formattedDate = fmt.format(myDate);
System.out.println(formattedDate); //06-04-2007 07:05:23:123
import java.util.*;
public class Time {
public static void main(String[] args) {
Long l = 0L;
Calendar c = Calendar.getInstance();
//milli sec part of current time
l = c.getTimeInMillis() % 1000;
//current time without millisec
StringBuffer sb = new StringBuffer(c.getTime().toString());
//millisec in string
String s = ":" + l.toString();
//insert at right place
sb.insert(19, s);
//ENJOY
System.out.println(sb);
}
}