Java GregorianCalendar and DST Cutover Times - java

I have a GregorianCalendar that I am am trying to set the time on. I am getting the date from one calendar and the time from another calendar. It mostly works, except for the 2AM hour of the DST switch day.
For example, with a date of 3/10/2013, a time of 2:40AM and a target output of 3/10/2013 2:40AM, I get 3/10/2013 3:40AM:
GregorianCalendar reportingDate = //some instance with a relevant date (in this case 3/10/2013)
GregorianCalendar targetTime = //some instance with a relevant time (in this case 2:40AM)
Calendar combination = Calendar.getInstance();
combination.set(Calendar.YEAR, reportingDate.get(Calendar.YEAR));
combination.set(Calendar.MONTH, reportingDate.get(Calendar.MONTH));
combination.set(Calendar.DAY_OF_YEAR, reportingDate.get(Calendar.DAY_OF_YEAR));
combination.set(Calendar.HOUR, targetTime.get(Calendar.HOUR));
combination.set(Calendar.AM_PM, targetTime.get(Calendar.AM_PM));
combination.set(Calendar.MINUTE, targetTime.get(Calendar.MINUTE));
combination.set(Calendar.SECOND, targetTime.get(Calendar.SECOND));
As soon as the code sets the AM_PM on the combination Calendar the time switches to 3:40AM. I would like it to not switch. I think this has to do with the target time Calendar being created as a time on the epoch date, but I would like the target time's specific date to not really matter...

Based on this output... I would think this is just how Java deals with DST? Seems like 2-3 AM goes into oblivion
See my comment below
final Calendar reportingDate = Calendar.getInstance();
reportingDate.set(Calendar.YEAR, 2013);
reportingDate.set(Calendar.MONTH, Calendar.MARCH);
reportingDate.set(Calendar.DAY_OF_MONTH, 10);
final Calendar targetTime = Calendar.getInstance();
targetTime.set(Calendar.AM_PM, Calendar.AM);
targetTime.set(Calendar.HOUR_OF_DAY, 3);
targetTime.set(Calendar.MINUTE, 0);
targetTime.set(Calendar.SECOND, 0);
targetTime.set(Calendar.MILLISECOND, 0);
final Calendar combination = Calendar.getInstance();
combination.set(Calendar.YEAR, reportingDate.get(Calendar.YEAR));
combination.set(Calendar.MONTH, reportingDate.get(Calendar.MONTH));
combination.set(Calendar.DAY_OF_YEAR, reportingDate.get(Calendar.DAY_OF_YEAR));
combination.set(Calendar.HOUR, targetTime.get(Calendar.HOUR));
combination.set(Calendar.AM_PM, targetTime.get(Calendar.AM_PM));
combination.set(Calendar.MINUTE, targetTime.get(Calendar.MINUTE));
combination.set(Calendar.SECOND, targetTime.get(Calendar.SECOND));
combination.set(Calendar.MILLISECOND, targetTime.get(Calendar.MILLISECOND));
final long timeAtCombined = combination.getTimeInMillis();
final SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss.SSSZ");
sdf.setTimeZone(TimeZone.getTimeZone("US/Eastern"));
// subtract one minute
System.out.println(sdf.format(combination.getTime()));
combination.add(Calendar.MILLISECOND, -1);
System.out.println(sdf.format(combination.getTime()));
// millis # 3
System.out.println(sdf.format(new Date(timeAtCombined)));
// millis # 3 - 1ms
System.out.println(sdf.format(new Date(timeAtCombined - 1)));
Output
03/10/2013 03:00:00.000-0400
03/10/2013 01:59:59.999-0500
03/10/2013 03:00:00.000-0400
03/10/2013 01:59:59.999-0500

You're setting everything, except for the time zone (which contains the DST). Set that as well, and you should be okay.

This isn't really an answer to your question directly but you can avoid all of this craziness by going with Joda Time
They have really nailed the date/time/calendar thing down.

Related

Java Date which looks same in any timezone

I am currently trying to get create a java Date which looks the same no matter what timezone I view it in. My current code is:
Calendar cal = Calendar.getInstance();
cal.set(2015, Calendar.JANUARY, 8, 0, 0, 0);
cal.set(Calendar.MILLISECOND, 0);
Date date = cal.getTime();
In my current timeZone this gives me '2015-01-08T00:00:00Z'In another this gives me 2015-01-08T00:00:00-03:00. What I want to know is if there is any way to drop the timezone part so as the time is the same in both time zones.
I would be VERY grateful for any help on this matter. Thank you.
Java SE 8 comes with a new Date & Time API. Have a look at LocalDate and LocalDateTime.
If you are only interested in the format of the time, create a java.text.SimpleDateFormat object to print your time in the format that you want.
http://docs.oracle.com/javase/1.5.0/docs/api/java/text/SimpleDateFormat.html
If you want the time to be printed with the same numbers no matter the TimeZone,
Use String ids[] = java.util.TimeZone.getAvailableIDs();
to get the TimeZone's IDs and find the ID that you want.
In this example, I created two SimpleDateFormat objects set to two different TimeZones. They both print off the same Calendar object. I have taken off the Z in ft2 to remove the time zone portion. By relying on toString(), I think you would be subject to Locale differences in displaying dates, like US MM/dd/yyyy and UK dd/MM/yyyy.
TimeZone tz = TimeZone.getTimeZone("America/New_York");
TimeZone tz2 = TimeZone.getTimeZone("America/Chicago");
Calendar acal = new GregorianCalendar();
SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd'T'hh:mm:ss Z");
ft.setTimeZone(tz);
SimpleDateFormat ft2 = new SimpleDateFormat ("yyyy-MM-dd'T'hh:mm:ss");
ft2.setTimeZone(tz2);
String date1 = ft.format(acal.getTime());
System.out.println(date1);
String date2 = ft2.format(acal.getTime());
System.out.println(date2);
Output:
2015-01-08T10:36:39 -0500
2015-01-08T09:36:39

How to reduce one month from current date and stored in date variable using java?

How to reduce one month from current date and want to sore in java.util.Date variable
im using this code but it's shows error in 2nd line
java.util.Date da = new Date();
da.add(Calendar.MONTH, -1); //error
How to store this date in java.util.Date variable?
Use Calendar:
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MONTH, -1);
Date result = cal.getTime();
Starting from Java 8, the suggested way is to use the Date-Time API rather than Calendar.
If you want a Date object to be returned:
Date date = Date.from(ZonedDateTime.now().minusMonths(1).toInstant());
If you don't need exactly a Date object, you can use the classes directly, provided by the package, even to get dates in other time-zones:
ZonedDateTime dateInUTC = ZonedDateTime.now(ZoneId.of("Pacific/Auckland")).minusMonths(1);
Calendar calNow = Calendar.getInstance()
// adding -1 month
calNow.add(Calendar.MONTH, -1);
// fetching updated time
Date dateBeforeAMonth = calNow.getTime();
you can use Calendar
java.util.Date da = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(da);
cal.add(Calendar.MONTH, -1);
da = cal.getTime();
Using new java.time package in Java8 and Java9
import java.time.LocalDate;
LocalDate mydate = LocalDate.now(); // Or whatever you want
mydate = mydate.minusMonths(1);
The advantage to using this method is that you avoid all the issues about varying month lengths and have more flexibility in adjusting dates and ranges. The Local part also is Timezone smart so it's easy to convert between them.
As an aside, using java.time you can also get the day of the week, day of the month, all days up to the last of the month, all days up to a certain day of the week, etc.
mydate.plusMonths(1);
mydate.with(TemporalAdjusters.next(DayOfWeek.SUNDAY)).getDayOfMonth();
mydate.with(TemporalAdjusters.lastDayOfMonth());
Using JodaTime :
Date date = new DateTime().minusMonths(1).toDate();
JodaTime provides a convenient API for date manipulation.
Note that similar Date API will be introduced in JDK8 with the JSR310.
You can also use the DateUtils from apache common. The library also supports adding Hour, Minute, etc.
Date date = DateUtils.addMonths(new Date(), -1)
raduce 1 month of JDF
Date dateTo = new SimpleDateFormat("yyyy/MM/dd").parse(jdfMeTo.getJulianDate());
Calendar cal = Calendar.getInstance();
cal.setTime(dateTo);
cal.add(Calendar.MONTH, -1);
Date dateOf = cal.getTime();
Log.i("dateOf", dateOf.getTime() + "");
jdfMeOf.setJulianDate(cal.get(Calendar.DAY_OF_YEAR), cal.get(Calendar.DAY_OF_MONTH),
cal.get(Calendar.DAY_OF_WEEK_IN_MONTH));

Incrementing date by 18years in java

1.I want to set the setMaxSelectableDate=18years in JDateChooser so i provided it the date by incrementing milliseconds but how should i increment it by 18years.
2.Incrementing by 18years the calculation comes out to be 365*18*24*60*60*1000=56764800000 which gives me error integer number to large.
Date max=new Date();
Date oth1=new Date(max.getTime() + (365*18*24*60*60*1000)); //days*hours*minutes*seconds*milliseconds
SimpleDateFormat maxdateFormatter1 = new SimpleDateFormat("MMM d,yyyy hh:mm:ss a");
String maxdate=maxdateFormatter1.format(oth1);
DateChooser_V1.setMaxSelectableDate(new java.util.Date(maxdate));
Let java.util.Calendar do this work for you:
Calendar c = Calendar.getInstance();
c.setTime(oldDate);
c.add(Calendar.YEAR, 18);
Date newDate = c.getTime();
Which takes care of leap years, historical GMT offset changes, historical Daylight Saving Time schedule changes etc.
You need to use a long. You can achieve this by adding an L to your number:
365L* ...
With JodaTime
DateTime in18Years = new DateTime( ).plusYears( 18 );
Here is how to convert to java.util.Date
Date in18Years = new DateTime( ).plusYears( 18 ).toDate( );
You cannot willy-nilly add seconds (or millseconds) and expect calendar calculations to come out right. Basically it takes some extra effort to account for all of those leap-years, leap seconds, and daylight savings shifts.
Until Java 1.8 comes out, use java.util.Calendar instead of java.util.Date, there are really good reasons that java.util.Date has practically everything in it deprecated. While it looks good in the beginning, with enough use you will find it often "just doesn't work (tm)".
GregorianCalendar now = new GregorianCalendar();
now.add(Calendar.YEAR, 18);
And that's assuming that you didn't overflow Integer.MAX_INT.
I would use a Calendar object to achieve this:
Calendar cal = Calendar.getInstance();
Date dt = new Date();
...
// Set the date value
...
cal.setTime(dt);
cal.add(Calendar.YEAR, +18);
dt = cal.getTime();
Hope this helps you

Java - Calculate Time from a timestamp of External Device with Different Epoch

So I'm kinda new to the Calendar/Time/Date stuff in Java but I've read a lot about them on the net.
Here is what I have to do:
I have an external device which sends an Avl Data Packet to my Communication Server and I'm on the parsing process of the Data part.
Somewhere in the Data Packet the device sends a timestamp of 32 bits which I have to parse/translate into the time the Record of the point from the GPS was saved.
The timestamp gives me seconds from 2007.01.01 00:00 UTC
Now here is a sample code that I felt that was the closest one I tried of the rest of the experiments..
DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss.SSS");
long now = (long)(TimeStampSeconds.longValue() * 1000);
Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.set(2007, 0, 1);
calendar.setTimeInMillis(now);
System.out.println(now + " = " + formatter.format(calendar.getTime()));
After that I found out that the calendar.set doesnt make a new epoch and so the .setTimeInMills doesnt work.Though I get some crazy results like:
Binary Timestamp is : 0000101011000001010110001111011100001111
SECONDS: 46193506063
46193506063000 = 25/10/3433 04:27:43.000
Shouldn't I just be missing just the 37 years between 1970 and 2007??
I want to find a way of finding the time from the seconds I get from the device but they have epoch 1/1/2007 and java has epoch 1/1/1970..
EDIT: What I want is to have time:1/1/2007 PLUS the timestamp's time. Hope I clarified the question a bit..
Someone any ideas??
Thx in Advance
It seems what you want to do is just to add your now value to the Calendar. This is easily done:
DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss.SSS");
long now = (long)(TimeStampSeconds.longValue() * 1000);
Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.set(2007, 0, 1);
calendar.setTimeInMillis(calendar.getTimeInMillis() + now);
System.out.println(now + " = " + formatter.format(calendar.getTime()));
EDIT
Something is weird regarding what your now variable holds. 46193506063 seconds corresponds to 1464.786468258 years according to this time converter.
Assuming you read the input in a timestamp long variable, I'd do something like:
Calendar theirEpoch = Calendar.getInstance();
theirEpoch.set(2007, 0, 1);
Calendar myEpoch = Calendar.getInstance();
myEpoch.set(1970, 0, 1);
long difference = myEpoch.getTimeInMillis() - theirEpoch.getTimeInMillis();
Calendar result = Calendar.getInstance();
result.setTimeInMillis(timestamp + difference);
I didn't test it, but it should give you the idea. Note also that I didn't take time zones into account.
This is the correct way to do what you want:
Calendar cal = Calendar.getInstance();
cal.set(2007, 1, 1, 0 ,0 ,0);
cal.set(Calendar.MILLISECOND, 0);
cal.add(Calendar.MILLISECOND, theirEpoch);
If their epoch is in seconds, change the last MILISECOND to SECOND.
The easiest thing to do is to use the roll() method of Calendar after setting the time in milliseconds:
calendar.roll(Calendar.YEAR, 37) --> just adds 37 years to your date ;-)
But I think your input data is wrong : if you take the number of seconds that have past since 01/01/2007 until now , it should be about 200 million and not 40 billion like in your example ...

Number of seconds in "HH:MM:SS"

What's the best way to get the number of seconds in a string representation like "hh:mm:ss"?
Obviously Integer.parseInt(s.substring(...)) * 3600 + Integer.parseInt(s.substring(...)) * 60 + Integer.parseInt(s.substring(...)) works.
But I don't want to test that, and reinvent the wheal, I expect there is a way to use DateTimeFormat or other classes from standard libraries.
Thanks!
Based on pakores solution:
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
Date reference = dateFormat.parse("00:00:00");
Date date = dateFormat.parse(string);
long seconds = (date.getTime() - reference.getTime()) / 1000L;
reference is used to compensate for different timezones and there is no problem with daylight saving time because SimpleDateFormat does NOT use the actual date, it return the Epoc date (January 1st, 1970 = no DST).
Simplifying (not much):
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = dateFormat.parse("01:00:10");
long seconds = date.getTime() / 1000L;
but I would still have a look at Joda-Time...
An original way:
The Calendar version (updated with the suggestions in the comments):
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = dateFormat.parse(string);
//Here you can do manually date.getHours()*3600+date.getMinutes*60+date.getSeconds();
//It's deprecated to use Date class though.
//Here it goes an original way to do it.
Calendar time = new GregorianCalendar();
time.setTime(date);
time.setTimeZone(TimeZone.getTimeZone("UTC"));
time.set(Calendar.YEAR,1970); //Epoc year
time.set(Calendar.MONTH,Calendar.JANUARY); //Epoc month
time.set(Calendar.DAY_OF_MONTH,1); //Epoc day of month
long seconds = time.getTimeInMillis()/1000L;
Disclaimer: I've done it by heart, just looking at the documentation, so maybe there is a typo or two.
joda-time is 1 options. infact i prefer that library for all date manipulations. I was going thru the java 5 javadoc and found this enum class which is simple and useful for you. java.util.concurrent.TimeUnit. look at the convert(...) methods. http://download.oracle.com/docs/cd/E17476_01/javase/1.5.0/docs/api/java/util/concurrent/TimeUnit.html
Here is the link to a Java example of time formatting.
http://download.oracle.com/docs/cd/E17409_01/javase/tutorial/i18n/format/simpleDateFormat.html

Categories