I'm trying to parse date like this:
DateFormat df = new SimpleDateFormat("MMM dd, yyyy K:mm:ss,SSS a z", Locale.ENGLISH);
Date date = df.parse("Oct 04, 2015 2:11:58,757 AM UTC");
And I'm getting a value of 5 hours am, because i live in UTC+3 timezone. But i need to have value of 2am, however, with the same format string(date string given in a specified format, which i'm not allowed to change). How to do this?
Upd: I don't need to format the date in proper timezone, i need to COMPARE these dates by its values without timezones. I want exactly that date have parsed ignoring the timezone in original string - and be always in the same timezone (my, for example), no matter what contains original string: UTC or UTC+3 or something else.
The accepted Answer is working too hard. Manipulating offsets is the province of a date-time library. Doing such work yourself is a waste of your time, and likely to be a source of bugs.
The old java.util.Date/.Calendar classes are notoriously troublesome. Avoid them. Instead use either java.time or Joda-Time.
java.time
Java 8 and later has a new java.time framework built-in.
Confused Question
Your Question is confused. You say you want to ignore time zone, yet you accept an answer that does indeed parse and process the time zone. And that answer then adjusts the result by an offset. So, it seems that you do not want to ignore the time zone.
Indeed, ignoring the time zone rarely makes sense. Perhaps you want to compare a pair of factories in Berlin and in Detroit to see if they both take a lunch break at the same time. In this case you are comparing their respective wall-clock time. The java.time framework offers the “Local” classes for this purpose: LocalDate, LocalTime, and LocalDateTime. But this is rarely needed in most business scenarios in my experience. These objects are not tied to the timeline.
So it seems that what you do want is to be able to compare date-time values across various time zones. The java.time classes do that implicitly. ZonedDateTime objects with various assigned time zones can be compared to one another with isBefore, isAfter, and isEqual methods.
Example Code
First we parse the input string.
The z pattern code means to expect and parse a time zone. The resulting date-time object will also be assigned this object if no other specific time zone is specified.
We also assign a Locale object with a human language component matching the text we expect to see in the input string. In this case, we need any Locale with English.
String input = "Oct 04, 2015 2:11:58,757 AM UTC";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "MMM dd, yyyy K:mm:ss,SSS a z" ).withLocale( Locale.ENGLISH );
ZonedDateTime then = ZonedDateTime.parse( input, formatter );
Next we get the current time for Québec. This arbitrary choice of time zone will demonstrate further below that we can compare this ZonedDateTime object to another with a different time zone. Specifically, comparing against the UTC time zone assigned to our then object above.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime now = ZonedDateTime.now( zoneId );
Do the comparison.
Boolean isThenBeforeNow = then.isBefore( now );
By the way, generally-speaking, the best practice in date-time work is to convert all your date-time values to UTC time zone for business logic, storage, and data exchange. Adjust into a time zone only as need be to satisfy a user’s expectations on-screen or in reports.
ZonedDateTime nowUtc = now.withZoneSameInstant( ZoneOffset.UTC );
Dump to console.
System.out.println( "input: " + input );
System.out.println( "then: " + then );
System.out.println( "now: " + now );
System.out.println( "isThenBeforeNow: " + isThenBeforeNow );
System.out.println( "nowUtc: " + nowUtc );
When run.
input: Oct 04, 2015 2:11:58,757 AM UTC
then: 2015-10-04T02:11:58.757Z[UTC]
now: 2015-10-19T19:28:04.619-04:00[America/Montreal]
isThenBeforeNow: true
nowUtc: 2015-10-19T23:28:04.619Z
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.
Upd2: Solved
Okay, now i get what i want:
DateFormat df = new SimpleDateFormat("MMM dd, yyyy K:mm:ss,SSS a z", Locale.ENGLISH);
Date date = df.parse("Oct 04, 2015 2:11:58,757 AM UTC");
long diff = TimeZone.getDefault().getRawOffset() - df.getTimeZone().getRawOffset();
date = new Date(date.getTime()-diff);
Anyway, thanks for everyone
Related
I need to convert a unix timestamp to a date object.
I tried this:
java.util.Date time = new java.util.Date(timeStamp);
Timestamp value is: 1280512800
The Date should be "2010/07/30 - 22:30:00" (as I get it by PHP) but instead I get Thu Jan 15 23:11:56 IRST 1970.
How should it be done?
For 1280512800, multiply by 1000, since java is expecting milliseconds:
java.util.Date time=new java.util.Date((long)timeStamp*1000);
If you already had milliseconds, then just new java.util.Date((long)timeStamp);
From the documentation:
Allocates a Date object and
initializes it to represent the
specified number of milliseconds since
the standard base time known as "the
epoch", namely January 1, 1970,
00:00:00 GMT.
java.time
Java 8 introduced a new API for working with dates and times: the java.time package.
With java.time you can parse your count of whole seconds since the epoch reference of first moment of 1970 in UTC, 1970-01-01T00:00Z. The result is an Instant.
Instant instant = Instant.ofEpochSecond( timeStamp );
If you need a java.util.Date to interoperate with old code not yet updated for java.time, convert. Call new conversion methods added to the old classes.
Date date = Date.from( instant );
This is the right way:
Date date = new Date ();
date.setTime((long)unix_time*1000);
tl;dr
Instant.ofEpochSecond( 1_280_512_800L )
2010-07-30T18:00:00Z
java.time
The new java.time framework built into Java 8 and later is the successor to Joda-Time.
These new classes include a handy factory method to convert a count of whole seconds from epoch. You get an Instant, a moment on the timeline in UTC with up to nanoseconds resolution.
Instant instant = Instant.ofEpochSecond( 1_280_512_800L );
instant.toString(): 2010-07-30T18:00:00Z
See that code run live at IdeOne.com.
Asia/Kabul or Asia/Tehran time zones ?
You reported getting a time-of-day value of 22:30 instead of the 18:00 seen here. I suspect your PHP utility is implicitly applying a default time zone to adjust from UTC. My value here is UTC, signified by the Z (short for Zulu, means UTC). Any chance your machine OS or PHP is set to Asia/Kabul or Asia/Tehran time zones? I suppose so as you report IRST in your output which apparently means Iran time. Currently in 2017 those are the only zones operating with a summer time that is four and a half hours ahead of 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 3-4 letter abbreviation such as EST or IST or IRST as they are not true time zones, not standardized, and not even unique(!).
If you want to see your moment through the lens of a particular region's time zone, apply a ZoneId to get a ZonedDateTime. Still the same simultaneous moment, but seen as a different wall-clock time.
ZoneId z = ZoneId.of( "Asia/Tehran" ) ;
ZonedDateTime zdt = instant.atZone( z ); // Same moment, same point on timeline, but seen as different wall-clock time.
2010-07-30T22:30+04:30[Asia/Tehran]
Converting from java.time to legacy classes
You should stick with the new java.time classes. But you can convert to old if required.
java.util.Date date = java.util.Date.from( instant );
Joda-Time
UPDATE: The Joda-Time project is now in maintenance mode, with the team advising migration to the java.time classes.
FYI, the constructor for a Joda-Time DateTime is similar: Multiply by a thousand to produce a long (not an int!).
DateTime dateTime = new DateTime( ( 1_280_512_800L * 1000_L ), DateTimeZone.forID( "Europe/Paris" ) );
Best to avoid the notoriously troublesome java.util.Date and .Calendar classes. But if you must use a Date, you can convert from Joda-Time.
java.util.Date date = dateTime.toDate();
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.
Looks like Calendar is the new way to go:
Calendar mydate = Calendar.getInstance();
mydate.setTimeInMillis(timestamp*1000);
out.println(mydate.get(Calendar.DAY_OF_MONTH)+"."+mydate.get(Calendar.MONTH)+"."+mydate.get(Calendar.YEAR));
The last line is just an example how to use it, this one would print eg "14.06.2012".
If you have used System.currentTimeMillis() to save the Timestamp you don't need the "*1000" part.
If you have the timestamp in a string you need to parse it first as a long: Long.parseLong(timestamp).
https://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html
Date's constructor expects the timeStamp value to be in milliseconds.
Multiply your timestamp's value with 1000, then pass it to the constructor.
If you are converting a timestamp value on a different machine, you should also check the timezone of that machine. For example;
The above decriptions will result different Date values, if you run with EST or UTC timezones.
To set the timezone; aka to UTC,
you can simply rewrite;
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
java.util.Date time= new java.util.Date((Long.parseLong(timestamp)*1000));
For kotlin
fun unixToDate(timeStamp: Long) : String? {
val time = java.util.Date(timeStamp as Long * 1000)
val sdf = SimpleDateFormat("yyyy-MM-dd")
return sdf.format(time)
}
Sometimes you need to work with adjustments.
Don't use cast to long! Use nanoadjustment.
For example, using Oanda Java API for trading you can get datetime as UNIX format.
For example: 1592523410.590566943
System.out.println("instant with nano = " + Instant.ofEpochSecond(1592523410, 590566943));
System.out.println("instant = " + Instant.ofEpochSecond(1592523410));
you get:
instant with nano = 2020-06-18T23:36:50.590566943Z
instant = 2020-06-18T23:36:50Z
Also, use:
Date date = Date.from( Instant.ofEpochSecond(1592523410, 590566943) );
LocalDateTime is another choice, like:
LocalDateTime.ofInstant(Instant.ofEpochSecond(unixtime), ZoneId.systemDefault())
Date d = new Date(i * 1000 + TimeZone.getDefault().getRawOffset());
Hi i am trying to get the current year in the below code however it is returning a 1970 year instead of 2020 last month this was working correctly but since we in January 2020, it is now returning a date from 1970, please assist
public String firstDateOfNextMonth(){
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
Calendar today = Calendar.getInstance();
Calendar next = Calendar.getInstance();
today.clear();
Date date;
next.clear();
next.set(Calendar.YEAR, today.get(Calendar.YEAR));
next.set(Calendar.MONTH, today.get(Calendar.MONTH)+ 1);
next.set(Calendar.DAY_OF_MONTH, 1);
date = next.getTime();
Log.d(TAG, "The Date: " + dateFormat.format(date));
return dateFormat.format(date);
}
If you have Java 8 or above, then you have java.time and you won't have to rely on outdated datetime implementations and you can do it this way:
public static String getFirstOfNextMonth() {
// get a reference to today
LocalDate today = LocalDate.now();
// having today,
LocalDate firstOfNextMonth = today
// add one to the month
.withMonth(today.getMonthValue() + 1)
// and take the first day of that month
.withDayOfMonth(1);
// then return it as formatted String
return firstOfNextMonth.format(DateTimeFormatter.ISO_LOCAL_DATE);
}
which prints the following when called today (2020-01-03) like System.out.println(getFirstOfNextMonth());:
2020-02-01
You might have to involve an external library, the ThreeTenAbp if you want it to work in Android below API level 26. Its use is explained in this question.
not sure why the today date gets cleared, remove today.clear() at line 4
today.clear(); initalize all elements of a date with the value 0
removing this line will give you the right answer
tl;dr
LocalDate // Represent a date-only value without a time-of-day and without a time zone.
.now( // Determine the current date as seen through the wall-clock time used by people in certain region (a time zone).
ZoneId.of( "America/Montreal" ) // Real time zone names have names in the format of `Continent/Region`. Never use 2-4 letter pseudo-zones such as `IST`, `PST`, or `CST`, which are neither standardized nor unique.
) // Return a `LocalDate`.
.with( // Move from one date another by passing a `TemporalAdjuster` implementation.
TemporalAdjusters // Class providing several implementations of `TemporalAdjuster`.
.firstDayOfNextMonth() // This adjuster finds the date of the first of next month, as its name suggests.
) // Returns another `LocalDate` object. The original `LocalDate` object is unaltered.
.toString() // Generate text in standard ISO 8601 format of YYYY-MM-DD.
See this code run live at IdeOne.com.
2020-02-01
Details
You are using terrible date-time classes that were made obsolete years ago by the unanimous adoption of JSR 310 defining the java.time classes.
The Answer by deHaar is correct. Here is an even shorter solution.
TemporalAdjuster
To move from one date to another, the java.time classes include the TemporalAdjuster interface. Pass one of these objects to the with method found on many of the other java.time classes.
TemporalAdjusters.firstDayOfNextMonth()
Several implementations of that interface are found in the class TemporalAdjusters (note the s plural). One of those is firstDayOfNextMonth(), just what you need.
Get today's date. A time zone is required, as for any given moment the date varies around the globe by time zone. If omitted, your JVM's current default time zone is implicitly applied. Better to be explicit.
ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
LocalDate today = LocalDate.now( z ) ;
Get your TemporalAdjuster object.
TemporalAdjuster ta = TemporalAdjusters.firstDayOfNextMonth() ;
Apply that adjuster to get another LocalDate object. Note that java.time classes are immutable by design. So we get a new object rather than altering the original.
LocalDate firstOfNextMonth = today.with( ta ) ;
We can shorten this code to a one-liner, if desired.
LocalDate firstOfNextMonth =
LocalDate
.now(
ZoneId.of( "Africa/Tunis" )
)
.with(
TemporalAdjusters.firstDayOfNextMonth()
)
;
Text
Your desired output format of YYYY-MM-DD complies with the ISO 8601 standard used by default in the java.time classes when parsing/generating text. So no formatting pattern need be specified.
String output = firstOfNextMonth.toString() ;
2020-02-01
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.
You are using Calendar.clear() which clears all the fields of your calendar, and essentially reverts it to 1/1/1970 (epoch time 0).
remove today.clear() and you'll get the correct answer
see more here
Remove next.clear();. As Calendar next= Calendar.getInstance(); initiates next with the current date, in your cases Fri Jan 03 2020 15:07:53. And when you do next.clear(), it sets to the inital epoch.
Epoch, also known as Unix timestamps, is the number of seconds (not
milliseconds!) that have elapsed since January 1, 1970 at 00:00:00 GMT
(1970-01-01 00:00:00 GMT).
I am trying to parse the String to date. String having date format as
"dd-MMM-yyyy Z" and String having value "12-DEC-2018 ET". Its giving the error
java.text.ParseException: Unparseable date: "12-DEC-2018 ET".
The same code is working for String having value "12-DEC-2018 IST".
below is the code snippet:
public static void main(String[] args) throws ParseException {
String dateInputIST ="12-DEC-2018 IST";
String dateInputET ="12-DEC-2018 ET";
SimpleDateFormat sdfmt1 = new SimpleDateFormat("dd-MMM-yyyy Z");
SimpleDateFormat sdfmt2= new SimpleDateFormat("dd/MM/yyyy");
Date dDate = sdfmt1.parse( dateInputIST );
String strOutput = sdfmt2.format( dDate );
System.out.println(strOutput);
Date etDate = sdfmt1.parse(dateInputET);
strOutput = sdfmt2.format(etDate);
System.out.println(strOutput);
}
Could someone please help. I needed to parse the time in any timezone.
Thanks,
Navin
Change
String dateInputET ="12-DEC-2018 ET";
to
String dateInputET ="12-DEC-2018 EDT";
'ET' is not a recognized time zone.
Pseudo-zones
ET, EST, and IST are not actually time zones. Those 2-4 letter pseudo-zones are not standardized and are not even unique! For example, IST can mean India Standard Time, Ireland Standard Time, Iceland Standard Time, and more.
Real time zone names take the format of Continent/Region such as Africa/Tunis.
Date & zone, separately
Date with time zone has no real meaning.
Handle the date as a LocalDate object.
String input = "12-DEC-2018"
DayeTimeFormatter f = DateTimeFormatter.ofPattern( "dd-MM-uuuu" , Locale.US ) ;
LocalDate ld = LocalDate.parse( input , f ) ;
Handle your desired time zone separately, as a ZoneId object.
ZoneId zNewYork = ZoneId.of( "America/New_York" ) ;
To combine, determine the first moment of the day.
ZonedDateTime zdtNewYork = ld.atStartOfDay( z ) ;
Generate text representing that moment in standard ISO 8601 format extended to append the name of the time zone in square brackets.
To see that same moment in UTC, extract a Instant.
Instant instant = zdtNewYork.toInstant() ;
Adjust into another zone.
ZonedDateTime zdtKolkata = instant.atZone( ZoneId.of( "Asia/Kolkata" ) ) ;
To focus on the date only, get a LocalDate for the day of that same moment when viewed through the lens of the wall-clock time used in India.
LocalDate ldKolkata = zdtKolkata.toLocalDate() ;
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.
java.time
DateTimeFormatter dateZoneFormatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("dd-MMM-uuuu v")
.toFormatter(Locale.ENGLISH);
String dateInputIST ="12-DEC-2018 IST";
String dateInputET ="12-DEC-2018 ET";
TemporalAccessor parsed = dateZoneFormatter.parse(dateInputIST);
System.out.println("Date: " + LocalDate.from(parsed) + " Time zone: " + ZoneId.from(parsed));
parsed = dateZoneFormatter.parse(dateInputET);
System.out.println("Date: " + LocalDate.from(parsed) + " Time zone: " + ZoneId.from(parsed));
On my computer the output from this snippet was:
Date: 2018-12-12 Time zone: Atlantic/Reykjavik
Date: 2018-12-12 Time zone: America/New_York
Format pattern letter v is for the generic time-zone name, that is, the name that is the same all year regardless of summer time (DST), for example Eastern Time or short ET.
If you want to control the interpretation of ambiguous time zone abbreviations (of which there are a lot), you may use the two-arg appendGenericZoneText(TextStyle, Set<ZoneId>) where the second argument contains the preferred zones. Still better if there is a way for you to avoid relying on time zone abbreviations altogether since, as I said, they are very often ambiguous.
I am not sure what sense a date with a time zone makes, though.
As an additional point, always specify locale for your formatters so they will also work if the default locale is changed or one day your program runs in a JVM with a different default locale.
Avoid SimpleDateFormat and Date
I don’t think SimpleDateFormat will be able to parse your string. It’s just the same since that class is already long outdated and is renowned for being troublesome, so you should never want to use it anyway.
I am trying to use mongodb to fetch some records with date fields, sample records are shown below, and want convert date field which has been parsed using jayway jsonpath to java.util.Date long integer. long integer converted does not match with the original one. Please help.
Sample records in tester collection:
{
"_id" : ObjectId("5b3fe6f91e618afb473dc644"),
"dateField" : ISODate("2018-07-06T15:46:55.819Z")
}
The Java code for getting records using jongo is as follows :
List<Tester> list= jongo.runCommand("{aggregate : 'tester',pipeline:[],cursor : {batchSize :10}}")
.field("cursor")
.as(Tester.class);
for(Tester t : list)
{
System.out.println("dateField test: : : : "+t.getDateField()+" : : : : "+t.getDateField().getTime());
// Output is perfectly fine : dateField test: : : : Fri Jul 06 21:16:55 IST 2018 : : : : 1530892015819
Gson gson = new Gson();
String str = gson.toJson(t);
DocumentContext docCtx = JsonPath.parse(str);
JsonPath jsonPath = JsonPath.compile("$.dateField");
Object obj = docCtx.read(jsonPath);
System.out.println(obj);
//After parsing with jsonPath the date is retained - Jul 6, 2018 9:16:55 PM
SimpleDateFormat format = new SimpleDateFormat("MMM dd, yyyy hh:mm:ss aaa");
Date d = format.parse(obj.toString());
System.out.println(d + " : : : " + d.getTime());
//Fri Jul 06 21:16:55 IST 2018 : : : 1530892015000 - Time is not retained
}
Expected :
t.getDateField().getTime() ==== d.getTime()
Please help
Regards
Kris
tl;dr
Your formatting pattern omits the fractional seconds, so no milliseconds appear in the output.
You are using obsolete date-time classes. Use java.time instead.
Example:
Instant // Represent a moment in UTC, with a resolution as fine as nanoseconds.
.parse( "2018-07-06T15:46:55.819Z" ) // Parse a string in standard ISO 8601 format. The `Z` on the end means UTC, pronounced “Zulu”.
.atZone( ZoneId.of( "Asia/Kolkata" ) ) // Adjust from UTC to a desired time zone. Same moment, same point on the timeline, different wall-clock time. Returns a `ZonedDateTime` object.
.toString() // Generate a String in standard ISO 8601 format. Represents the moment in our `ZonedDateTime` object.
Convert from legacy java.util.Date class to modern java.time.Instant, and back again. Example nonsense code:
java.util.Date.from( // Convert from modern `Instant` to legacy `Date`.
myJavaUtilDate.toInstant() // Convert from legacy `Date` to modern `Instant`.
)
java.time
You are using terribly troublesome old date-time classes: Date & SimpleDateFormat. These were supplanted years ago by the modern java.time classes.
Your input 2018-07-06T15:46:55.819Z is in standard ISO 8601 format. The java.time classes use the ISO 8601 formats by default when parsing or generating strings. So no need to specify a formatting pattern.
The Z on the end is pronounced Zulu and means UTC. The Instant class represents a moment in UTC.
Instant instant = Instant.parse( "2018-07-06T15:46:55.819Z" ) ;
Generate an output string in ISO 8601 format.
String output = instant.toString() ;
2018-07-06T15:46:55.819Z
Your code ignores the crucial issue of time zone. Rather than rely implicitly on the JVM’s current default time zone, be explicit with a ZoneId even if that is ZoneId.systemDefault().
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(!). For example, your IST could mean Irish Standard Time, India Standard Time, Iran Standard Time, or something else.
After adjusting from UTC to a specific time zone, we still have the same moment, the same point on the timeline. Only the wall-clock time is different.
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ; // Or `ZoneId.systemDefault()`.
ZonedDateTime zdt = instant.atZone( z ) ; // Adjust from UTC to a specific time zone.
Generate an output string in ISO 8601 format extended to append the name of the time zone in square brackets.
String output = zdt.toString() ;
2018-07-06T21:16:55.819+05:30[Asia/Kolkata]
Notice your fractional second (milliseconds) is still intact.
Converting
Perhaps you must interface with an java.util.Date (your Question is not clear), because of old code not yet updated to support java.time.
You will find convenient conversion methods, new methods added to the old classes.
Going from java.util.Date to java.time.Instant.
Instant myInstant = myJavaUtilDate.toInstant() ;
Proceed as shown above. Adjust into your desired time zone, and generate a String.
Going the other direction, from the modern Instant class to the legacy class Date.
java.util.Date myDate = java.util.Date.from( myInstant ) ;
Immutable objects
The java.time classes are designed to be thread-safe, and use the immutable objects pattern. Notice how the code above produces fresh objects based on the original’s values, rather than altering (“mutating”) the original.
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.
new SimpleDateFormat("MMM dd, yyyy hh:mm:ss aaa");
You are discarding the milliseconds part of the input, which results in exactly the difference you see. Use this instead:
new SimpleDateFormat("MMM dd, yyyy hh:mm:ss.SSS aaa");
^^^^
I'm all clear on the fact that java.util.Date doesn't have timezone and why so.
I've an application where the user has set his TimeZone, and when he selects Date in a DateTime picker, the component returns a Date object to me.
I then need to modify the date as to save the UTC equivalent in database.
It's pretty simple to get a Date object representing UTC date for a local timezone with org.joda.time :
public static final Date getTimeZoneDependantDate(Date pDateUtc, String pUserTimezoneValue) {
// Build the DateTime Object
DateTime originalDate = new DateTime(pDateUtc.getTime(), DateTimeZone.forID(PREF_TIMEZONE_DEF_VALUE));
// Convert the Date
DateTime convertedDate = originalDate.withZone(DateTimeZone.forID(pUserTimezoneValue));
// Return the localTime associated with the timeZone
return convertedDate.toLocalDateTime().toDate();
}
But I'm stuck on how to do the opposite, change the Date picked by the user (from his timezone perspective) to UTC.
Since LocalDateTime takes the instant and not the local Date as a parameter.
Is there any cleaner way than to parse String ?
tl;dr
You do not provide enough info. Report:
The results of this: myJavaUtilDate.toInstant().toString()
The inputs to the component
The current default time zone of the app
Details
You do not really give enough information about your problem. Are you getting a correct date-time value in UTC via the java.util.Date object from your GUI component or not?
If the user in Québec time zone of America/Montreal entered 9 AM on December 1, 2016, and your component is correctly adjusting those values into UTC while producing the java.util.Date object, then you have no problem. The UTC value would be 2 PM in the afternoon for UTC, as America/Montreal is five hours behind UTC on that particular date. Just pass the Date object to the database after converting to a java.sql.Timestamp object.
FYI, both the old date-time classes classes (Date & Calendar etc.) and Joda-Time are now supplanted by the java.time classes. Here is some example code in java.time showing the kind of behavior your component is hopefully employing.
LocalDate ld = LocalDate.of ( 2016 , Month.DECEMBER , 1 );
LocalTime lt = LocalTime.of ( 9 , 0 );
ZoneId z = ZoneId.of ( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.of ( ld , lt , z );
Instant instant = zdt.toInstant (); // UTC
System.out.println ( "zdt.toString(): " + zdt );
System.out.println ( "instant.toString(): " + instant );
zdt.toString(): 2016-12-01T09:00-05:00[America/Montreal]
instant.toString(): 2016-12-01T14:00:00Z
The Z on the end of the string is short for Zulu and means UTC.
Given the unfortunate behavior of java.util.Date::toString to apply your current default time zone while generating the string, I suggest you convert your Date to an Instant so you can get a clear reading of its value.
Instant instantConvertedFromDateOfComponent = myJavaUtilDate.toInstant();
If after this step you do indeed see 2 PM in the afternoon, then all is well and your component is performing well.
If your component is acting badly, ignoring the issue of time zone and reporting your user’s input as if the user intended UTC as their own zone, then you will see 2016-12-01T09:00:00Z. That is a problem. The workaround is to make the time zone adjustment yourself. Extract the “local” (zone-less) values, then apply the intended time zone.
To get the “local” date and time, first convert to OffsetDateTime object.
OffsetDateTime odt = instantConvertedFromDateOfComponent.atOffset( ZoneOffset.UTC );
LocalDateTime ldt = odt.toLocalDateTime(); // 2016-12-01T09:00:00Z
ZonedDateTime zdt = ldt.atZone( z ); // 2016-12-01T09:00-05:00[America/Montreal]
If your JDBC driver complies with JDBC 4.2 or later, you may be able to pass these java.time types directly. If not, convert to java.sql types via new methods added to the old classes. Discussed already many times on Stack Overflow, so search for more info.
The server’s current default time zone should be irrelevant to your programming. Always specify explicitly the desired/expected time zone in optional arguments rather than rely implicitly on 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.
Where to obtain the java.time classes?
Java SE 8 and SE 9 and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
The best way of transmitting and saving the date over network is in the form of timestamp (date in milliseconds) this timestamp does not need any timezone information. But after fetching the date in the form of timestamp use it create date object, If you want to show the date in the UTC format then only you need to convert it.