date + time can't convert to milliseccond - java

int year = Integer.parseInt(sTransDateTime2.substring(0, 4));
int month = (Integer.parseInt(sTransDateTime2.substring(4, 6)) - 1);
int day = Integer.parseInt(sTransDateTime2.substring(6, 8));
int hour = Integer.parseInt(sTransDateTime2.substring(8, 10));
int minute = Integer.parseInt(sTransDateTime2.substring(10, 12));
int second = Integer.parseInt(sTransDateTime2.substring(12));
System.out.println("year=" + year + "| month= " + month + "| day=" + day);
DateFormat df = new SimpleDateFormat("mm/dd/yyyy");
Calendar calConvert = Calendar.getInstance();
calConvert.set(year, month, day, hour, minute, second);
sTransDateTime2 = Long.toString(calConvert.getTimeInMillis() / 1000);
System.out.println("debug date: " + sTransDateTime2);
my date time is year=2017| month= 7| day=28| hour= 17| minute=0,
After convert to milliseconds it become 1501232400.
The result of date is correct, will be 28 Jul 2017, but time become 9.00pm.
Any wrong on my coding?
Thanks

stop learning the old broken java.date and move into the java.time
LocalDateTime myldt = LocalDateTime.of(2017, 7, 28, 17, 0);
System.out.println(myldt);
System.out.println(myldt.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());

It looks like the conversion to milliseconds is being done in one TimeZone, but the system on which the milliseconds are converted to date is in a different timezone.
28th July, 2017 17:00:00 gives seconds from epoch as 1501232400 when in UTC+08:00 timezone, but these seconds from epoch give back 28th July, 2017 21:00:00 in UTC+12:00 timezone.
To illustrate the above, I have explicitly set the timezone to UTC+8:00 when calculating the milliseconds. (I have set my system timezone to UTC+12:00 to show the output)
System.out.println("year=" + year + "| month= " + month + "| day=" + day);
Calendar calConvert = Calendar.getInstance();
calConvert.setTimeZone(TimeZone.getTimeZone("GMT+8:00"));
calConvert.set(year, month, day, hour, minute, second);
sTransDateTime2 = Long.toString(calConvert.getTimeInMillis() / 1000);
System.out.println("debug date: " + sTransDateTime2);
System.out.println(new Date(calConvert.getTimeInMillis()));
This gives me the output as below:
year=2017| month= 6| day=28
debug date: 1501232400
Fri Jul 28 21:00:00 NZST 2017
Please note that Date always prints the date in local timezone. So, it has converted the milliseconds as per local timezone and the time changes to 21:00.
Now I format this date to make sure that I get the output back in UTC+08:00 only, whatever be the system timezone.
Date dt = calConvert.getTime();
DateFormat formatter= new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
formatter.setTimeZone(TimeZone.getTimeZone("GMT+8:00"));
System.out.println(formatter.format(dt));
Now I get the output as : 07/28/2017 17:00:00 instead of the earlier date with 21:00 as time.
So, the conclusion is that you need to format the date to be displayed in a specific timezone, if you want to avoid it picking up the default timezone of the system on which it is displayed.
To avoid all the cumbersome code and confusing issues, as suggested in the other answer, go for the java.time API. java.time is available from JDK 8. As you are using JDK 6, you can use the ThreeTen Backport. Just to illustrate the ease with which things could be done with java.time , the following does the same what your code does , but in a concise and easily understandable way:
ZonedDateTime zdt = ZonedDateTime.of(LocalDate.of(year, month, day),
LocalTime.of(hour, minute,second), ZoneId.of("Asia/Macau"));
long secondsFromEpoch = zdt.toEpochSecond();
//To convert back
ZonedDateTime zdtBack = Instant.ofEpochSecond(secondsFromEpoch)
.atZone(ZoneId.of("Asia/Macau"));
System.out.println(zdtBack);

Related

DateTimeFormatter and SimpleDateFormat produce different strings [duplicate]

This question already has answers here:
Why when year is less than 1884, it remove few milliseconds?
(2 answers)
Closed 3 years ago.
This is not a duplicate as some people think. It is about two standard Java classes for formatting dates that produce different strings for the same value of milliseconds since the epoch.
For values of milliseconds since the epoch that occur before some point in the year 1883, SimpleDateFormat and DateTimeFormatter will produce different results. For reasons I don't understand, DateTimeFormatter will produce strings that differ from what I expect by almost four minutes.
This is important because I am changing some code to use DateTimeFormatter instead of SimpleDateFormat. Our input is always milliseconds since the epoch, and I need the values to be the same after I change the code.
The previous code would create a Date from the milliseconds, then use SimpleDateFormat to format it.
The new code creates an Instant from the milliseconds, then a ZonedDateTime from the Instant, then a DateTimeFormatter to format it.
Here's a test I wrote using JUnit4 and Hamcrest. The test finds the milliseconds since the epoch for May 13, 15:41:25, for each year starting at 2019 and working backwards one year at a time.
For each year, it formats the milliseconds using SimpleDateFormat and DateTimeFormatter then compares the results.
#Test
public void testSimpleDateFormatVersusDateTimeFormatter() throws Exception {
String formatString = "EEE MMM dd HH:mm:ss zzz yyyy";
String timeZoneCode = "America/New_York";
ZoneId zoneId = ZoneId.of(timeZoneCode);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(formatString);
simpleDateFormat.setTimeZone(TimeZone.getTimeZone(timeZoneCode));
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(formatString);
for (int year = 0; year < 200; year++) {
long millis = getMillisSinceEpoch(2019 - year, 5, 13, 15, 41, 25, timeZoneCode);
System.out.printf("%s%n", new Date(millis));
// Format using a DateTimeFormatter;
Instant instant = Instant.ofEpochMilli(millis);
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant, zoneId);
String dateTimeFormatterString = dateTimeFormatter.format(zonedDateTime);
// Format using a SimpleDateFormat
Date date = new Date(millis);
String simpleDateFormatString = simpleDateFormat.format(date);
System.out.println("dateTimeFormatterString = " + dateTimeFormatterString);
System.out.println("simpleDateFormatString = " + simpleDateFormatString);
System.out.println();
assertThat(simpleDateFormatString, equalTo(dateTimeFormatterString));
}
}
private long getMillisSinceEpoch(int year, int month, int dayOfMonth, int hours, int minutes, int seconds, String timeZoneId) {
TimeZone timeZone = TimeZone.getTimeZone(timeZoneId);
Calendar calendar = Calendar.getInstance(timeZone);
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, month-1);
calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
calendar.set(Calendar.HOUR_OF_DAY, hours);
calendar.set(Calendar.MINUTE, minutes);
calendar.set(Calendar.SECOND, seconds);
return calendar.getTimeInMillis();
}
Running this you can see it passes for all years from 2019 back to 1884. So for any given year you see output like this:
Mon May 13 12:41:25 PST 1895
dateTimeFormatterString = Mon May 13 15:41:25 EST 1895
simpleDateFormatString = Mon May 13 15:41:25 EST 1895
But once it gets to 1883 it inexplicably fails:
Sun May 13 12:41:25 PST 1883
dateTimeFormatterString = Sun May 13 15:45:23 EST 1883
simpleDateFormatString = Sun May 13 15:41:25 EST 1883
java.lang.AssertionError:
Expected: "Sun May 13 15:45:23 EST 1883"
but: was "Sun May 13 15:41:25 EST 1883"```
The hours and seconds are obviously wrong.
By the way, if I change the time zone to "UTC", then the test passes.
According to https://www.timeanddate.com/time/change/usa/new-york?year=1883 (which was the first hit in a Google search for "1883 time adjustment"):
Nov 18, 1883 - Time Zone Change (LMT → EST)
When local standard time was about to reach
Sunday, November 18, 1883, 12:03:58 pm clocks were turned backward 0:03:58 hours to
Sunday, November 18, 1883, 12:00:00 noon local standard time instead.
3:58 matches the "almost four minutes" that you're seeing.
I haven't tested this, but I bet that if you iterate through months and days in addition to years, it occurs at that date.
See Also
Why when year is less than 1884, it remove few milliseconds?
Python pytz timezone conversion returns values that differ from timezone offset for different dates
Why is subtracting these two times (in 1927) giving a strange result? — a classic answered by Jon Skeet; not the same issue, but the same kind of issue
The Times Reports on "the Day of Two Noons"

Java convert data/time between timezone is inaccurate

TimeZone.setDefault(TimeZone.getTimeZone("Europe/Moscow"));
System.out.println("Default Timezone: " + TimeZone.getDefault());
String date = "08/04/2016 00:00:00";
SimpleDateFormat simpleDateFormatMoscow = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
Date moscowDt = simpleDateFormatMoscow.parse(date);
System.out.println("Moscow Date: " + simpleDateFormatMoscow.format(moscowDt));
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Bangkok"));
System.out.println("Bangkok Date: " + simpleDateFormat.format(moscowDt));
Calendar calendar = new GregorianCalendar();
calendar.setTime(moscowDt);
calendar.setTimeZone(TimeZone.getTimeZone("Asia/Bangkok"));
System.out.println("Bangkok Date: " + simpleDateFormat.format(calendar.getTime()));
System.out.println("Test Timezone");
System.out.println(TimeZone.getTimeZone("America/New_York"));
System.out.println(TimeZone.getTimeZone("Europe/Moscow"));
System.out.println(TimeZone.getTimeZone("Asia/Bangkok"));
I tried to use the code this snippet to convert date/time between Moscow and Bangkok. The result is as followed:
Default Timezone:
sun.util.calendar.ZoneInfo[id="Europe/Moscow",offset=14400000,dstSavings=0,useDaylight=false,transitions=78,lastRule=null]
Moscow Date: 08/04/2016 00:00:00
//util date/time
Bangkok Date: 08/04/2016 03:00:00
//joda time
Bangkok Date: 08/04/2016 03:00:00
However, when I convert date/time using https://singztechmusings.wordpress.com/2011/06/23/java-timezone-correctionconversion-with-daylight-savings-time-settings/ or google the time is
Moscow Date: 08/04/2016 00:00:00
Bangkok Date: 08/04/2016 04:00:00
Could anyone please tell me the correct way to convert data/time using java?
And Could anyone please tell me what I did wrong and why the result is inaccurate?
Your Java have wrong timezone offset: "offset=14400000" is 4 hours, but Moscow is UTC+3 for last year and a half.
Upgrade your java with tzupdater.
Java is using its own timezone data which is independenct from the host operation system. It might be inaccurate if you are not using the latest version of Java cause Russia (Europe/Moscow) has switched from daylight saving time to permanent standard time two years ago
This is one way to do it using your local time zone first.
public static void main(String[] args) {
// Create a calendar object and set it time based on the local time zone
Calendar localTime = Calendar.getInstance();
localTime.set(Calendar.HOUR, 17);
localTime.set(Calendar.MINUTE, 15);
localTime.set(Calendar.SECOND, 20);
int hour = localTime.get(Calendar.HOUR);
int minute = localTime.get(Calendar.MINUTE);
int second = localTime.get(Calendar.SECOND);
// Print the local time
System.out.printf("Local time : %02d:%02d:%02d\n", hour, minute, second);
// Create a calendar object for representing a Bangkok time zone. Then we set
//the time of the calendar with the value of the local time
Calendar BangkokTime = new GregorianCalendar(TimeZone.getTimeZone("Asia/Bangkok"));
BangkokTime.setTimeInMillis(localTime.getTimeInMillis());
hour = BangkokTime.get(Calendar.HOUR);
minute = BangkokTime.get(Calendar.MINUTE);
second = BangkokTime.get(Calendar.SECOND);
// Print the local time in Bangkok time zone
System.out.printf("Bangkok time: %02d:%02d:%02d\n", hour, minute, second);
//Then do the same for the Moscow time zone
Calendar MoscowTime = new GregorianCalendar(TimeZone.getTimeZone("Europe/Moscow"));
MoscowTime.setTimeInMillis(localTime.getTimeInMillis());
hour = MoscowTime.get(Calendar.HOUR);
minute = MoscowTime.get(Calendar.MINUTE);
second = MoscowTime.get(Calendar.SECOND);
// Print the local time in Moscow time zone
System.out.printf("Moscow time: %02d:%02d:%02d\n", hour, minute, second);
}

java.util.Date class with different approach for same date gives different output

public static void main(String[] args) throws ParseException {
// create a date
Date date = new Date();
long diff = date.getTime();
Date date1 = new Date(2013, 10, 1, 11, 6);
long diff1 = date1.getTime();
System.out.println("date is 1-10-2013, " + diff + " have passed.");
System.out.println("date is 1-10-2013, " + diff1 + " have passed.");
}
and the output is
date is 1-10-2013, 1380605909318 have passed.
date is 1-10-2013, 61341428160000 have passed.
Can anybody elaborate on the difference beween 1380605909318 and 61341428160000?
This line:
Date date1 = new Date(2013, 10, 1, 11, 6);
... doesn't do what you thing it does. That creates a Date object representing November 1st in the year 3913, at 11:06 local time. I don't think that's what you wanted.
Indeed, if you change your code to include the date itself rather than hard-coding what you think the right value will be, you'll see that:
System.out.println("date is " + date + ", " + diff + " have passed.");
System.out.println("date is " + date1 + ", " + diff1 + " have passed.");
There's a reason that constructor is deprecated - you should pay attention to deprecation, as well as to the documentation.
Now you could just use java.util.Calendar instead - but I'd actually recommend that you use Joda Time instead, if you possibly can. It's a much, much cleaner API than java.util.Calendar/Date. Alternative, if you can use a pre-release of Java 8, that has the new JSR-320 date/time API.
Just add this line
System.out.println("date is 1-10-2013, " + new Date(diff1) + " have passed.");
And you can see that the date is Sat Nov 01 11:06:00 IST 3913.
Date date1 = new Date(2013, 10, 1, 11, 6); is not what you thought it was. That's why you shouldn't use deprecated methods(constructor here).
As #JonSkeet mentioned, Joda is highly recommended over Java's Date.
Oddly, months are zero based, so your 10 in the constructor is actually month 11!
And it doesn't stop there: year is from 1900!
From the javadoc:
year - the year minus 1900.
month - the month between 0-11.
try
System.out.println("date is 1-10-2013, " + diff + " have passed.");
System.out.println("date is " + date1.toString() + diff1 + " have passed.");
and you will see the error.
According to the javadocs for thsi deprecated API, the year - the year minus 1900
http://docs.oracle.com/javase/6/docs/api/java/util/Date.html#Date(int, int, int, int, int)
Date.getTime() returns you date and time in milliseconds.
Javadoc says
Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
represented by this Date object.
#return the number of milliseconds since January 1, 1970, 00:00:00 GMT
represented by this date.
In second date, you are missing milliseconds as well
For the second date object, the first argument takes (the year minus 1900).
So in your case if you want 2013, you should pass 113
From java docs Date class
public Date(int year,int month,int date,int hrs,int min)
Parameters:
year - the year minus 1900.
month - the month between 0-11.
date - the day of the month between 1-31.
hrs - the hours between 0-23.
min - the minutes between 0-59.
#Deprecated
public Date(int year,
int month,
int date,
int hrs,
int min)
Deprecated. As of JDK version 1.1, replaced by Calendar.set(year + 1900, month, date, hrs, min) or GregorianCalendar(year + 1900, month, date, hrs, min).
Allocates a Date object and initializes it so that it represents the instant at the start of the minute specified by the year, month, date, hrs, and min arguments, in the local time zone.
Parameters:
year - the year minus 1900.
month - the month between 0-11.
date - the day of the month between 1-31.
hrs - the hours between 0-23.
min - the minutes between 0-59.
So if you want to get the same or very near results you have to use as following
Date date1 = new Date(113, 9, 1, 11, 6);

Time Zones in Java

I'm working on a security signature in java that also verifies the date and time the call is being made. The POST call arrives with something like
String date = "Sat, 27 Apr 2013 01:11:30 GMT"
SimpleDateFormat RFC1123Format = new SimpleDateFormat("EEE, dd MMM yyyyy HH:mm:ss z", Locale.US);
And I'm able to parse it
Calendar gmtTime = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
Date dateHeader = RFC1123Format.parse(date);
gmtTime.setTime(dateHeader);
System.out.println("Date Header (GMT TIME): " + gmtTime.getTimeInMillis() + " ms");
System.out.println("Hour of day (GMT TIME): " + gmtTime.get(Calendar.HOUR_OF_DAY));
Calendar currentTime = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
currentTime.setTimeInMillis(System.currentTimeMillis());
System.out.println("System Date (LA TIME): " + currentTime.getTimeInMillis() + " ms");
System.out.println("Hour of day (LA TIME): " + currentTime.get(Calendar.HOUR_OF_DAY));
currentTime.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("System Date (GMT TIME): " + currentTime.getTimeInMillis() + " ms");
System.out.println("Hour of day (GMT TIME): " + currentTime.get(Calendar.HOUR_OF_DAY));
System.out.println("Diff: " + Math.abs(gmtTime.getTimeInMillis() - currentTime.getTimeInMillis()));
However the printout I get differs by 1 entire hour.
Date Header (GMT TIME): 1367025090000 ms
Hour of day (GMT TIME): 1
System Date (LA TIME): 1367022298441 ms
Hour of day (LA TIME): 0
System Date (GMT TIME): 1367022298441 ms
Hour of day (GMT TIME): 0
Diff: 2791559
Any ideas?
You can use JodaTime >> http://joda-time.sourceforge.net/ that implements TimeZone Calculations more efficiently than Java calendar
You don't give your formatter the calendar that you are using to represent your timestamps.
In this case, your calendar is set to represent timestamps in GMT. GMT is a synonym for UTC and UTC never observes any adjustment for DST. Your formatter, however, by default must convert your supplied string with the system default calendar as the basis, which likely does observe DST.
If this is the case, you can get consistent reporting by making sure that your formatter is using the same calendar that you are using to represent your date/times. Try this:
SimpleDateFormat RFC1123Format = new SimpleDateFormat();
GregorianCalendar gc - new GregorianCalendar(TimeZone.getTimeZone("GMT"));
RFC1123Format.setCalendar(gc);
RFC1123Format.applyPattern("EEE, dd MMM yyyyy HH:mm:ss z");
gc.setTime(RFC1123Format.parse(yourDateString));
Fixed it myself by adding an extra verification to check if Daylight Savings is being observed. This is the final code:
Calendar gmtTime = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
Date dateHeader = RFC1123Format.parse(date);
gmtTime.setTime(dateHeader);
Calendar currentTime = Calendar.getInstance();
currentTime.setTimeInMillis(System.currentTimeMillis());
boolean DST = false;
if(currentTime.getTimeZone().inDaylightTime(currentTime.getTime())) {
DST = true;
}
currentTime.setTimeZone(TimeZone.getTimeZone("GMT"));
if(DST) {
currentTime.set(Calendar.HOUR_OF_DAY, currentTime.get(Calendar.HOUR_OF_DAY) + 1);
.
.
.
<code to handle last day of month and month change as a result of the hour adjustment>
}
Thanks #gangqinlaohu for your suggestion.

Formatting XmlGregorianCalendar timezone issue

I need to format java XmlGregorianCalendar to "yyMMdd" string.
My implementation:
XMLGregorianCalendar date = getDate(); //getting the date
if (date != null) {
SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
LOG.debug("Parsing date...");
LOG.debug("XML Date: " + date);
LOG.debug("XML Date timezone: " + date.getTimezone());
GregorianCalendar gc = date.toGregorianCalendar();
LOG.debug("Gregorian calendar: " + gc.toString());
LOG.debug("Gregorian calendar timezone id: " + gc.getTimeZone().getID());
Date d = gc.getTime();
LOG.debug("Date: " + d.toString());
String formatted = sdf.format(d);
LOG.debug("Formatted: " + formatted);
}
What I see in log:
Parsing date...
XML Date: 1943-04-15T00:00:00.000Z
XML Date timezone: 0
Gregorian calendar: java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="GMT+00:00",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=1943,MONTH=3,WEEK_OF_YEAR=1,WEEK_OF_MONTH=1,DAY_OF_MONTH=15,DAY_OF_YEAR=1,DAY_OF_WEEK=5,DAY_OF_WEEK_IN_MONTH=1,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=0,DST_OFFSET=0]
Gregorian calendar timezone id: GMT+00:00
Date: Wed Apr 14 20:00:00 EDT 1943
Formatted: 430414
April, 15 was parsed as April, 14. What I'm doing wrong? When I should set timezone?
It was parsed as midnight on April 15th UTC. It was then formatted as 8pm on April 14th EDT, which is correct as EDT is four hours behind UTC.
Note that Date.toString() always uses the local time zone - a Date object has no concept of which time zone it's in.
Your formatted value is also using the default time zone, as you haven't specified a time zone. The calendar value (gc) is in UTC, but when you format it, it will apply the time zone from the formatter (as you format the Date value, which doesn't have a time zone).
It's not clear what you were trying to achieve, but hopefully that will help. As an aside, I'd strongly recommend that you use Joda Time instead if you possibly can - it makes a lot of this much clearer.

Categories

Resources