wrong time calculating in Java - java

when I want to sum two dates in java it does not work:
System.out.println(date + " <---- date");
System.out.println(time + " <---- time");
System.out.println(new Date(date.getTime() + time.getTime()) + " <---- new Date(time.getTime() + date.getTime())");
leads to following output:
Wed Nov 06 00:00:00 CET 2013 <---- date
Thu Jan 01 11:51:14 CET 1970 <---- time
Wed Nov 06 10:51:14 CET 2013 <---- new Date(time.getTime() + date.getTime())
... but if i work with Calender it works!
Calendar calendar = Calendar.getInstance();
calendar.setTime(time);
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int min = calendar.get(Calendar.MINUTE);
calendar.setTime(date);
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, min);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
Date myDate = calendar.getTime();
System.out.println(myDate);
results in
Wed Nov 06 11:51:00 CET 2013
which is correct
Can anybody explain me why?

Fundamentally, you've got problems with time zones here. The fact that you're using a java.util.Date to represent a time of day is messing you up to start with. Your time of 11:51:14 CET is actually 10:51:14 UTC, so when you add the result of calling time.getTime(), you're only adding "just under 11 hours" rather than "just under 12 hours". The use of inappropriate data types makes all this hard to work with and understand.
I'd strongly recommend using Joda Time for all of this. Then you can start with a LocalDate and LocalTime, combine them into a LocalDateTime and then work out if you want to apply a particular time zone.
Using the right data types, which mean exactly what you're trying to convey, makes a huge difference for date/time work.

Related

SimpleDateFormat - Timezone not correct

I have a problem in parsing timestampls in Java.
I would expect to have both timestamps in the same timezone (CET).
SimpleDateFormat sdaf = new SimpleDateFormat ("dd.MM.yyyy HH:mm:ss");
String str = "30.03.2013 06:00:00";
sdaf.setTimeZone (TimeZone.getTimeZone ("CET"));
java.util.Date dat = sdaf.parse (str);
System.out.println (str + " = " + dat);
str = "31.03.2013 05:00:00";
sdaf.setTimeZone (TimeZone.getTimeZone ("CET"));
dat = sdaf.parse (str);
System.out.println (str + " = " + dat);
But that is not the case - see the output.
30.03.2013 06:00:00 = Sat Mar 30 06:00:00 CET 2013
31.03.2013 05:00:00 = Sun Mar 31 05:00:00 CEST 2013
EDIT:
If I change CET with GMT+1 I get this.
03.2013 06:00:00 = Sat Mar 30 06:00:00 CET 2013
31.03.2013 05:00:00 = Sun Mar 31 06:00:00 CEST 2013
Seems to be correct. But why is CET not working?
UTC+1 produces
30.03.2013 06:00:00 = Sat Mar 30 07:00:00 CET 2013
31.03.2013 05:00:00 = Sun Mar 31 07:00:00 CEST 2013
what is different to GMT+1 - ????
You can't get a CET time zone for the 31.03.2013 05:00:00 because it was not on that timezone anymore. To understand, just check the name of both timezone
CET : Central European Time (UTC+1 or GMT+1)
CEST : Central European Summer Time (UTC+2 or GMT+2)
That's the Saving Daylight Time that occured during the 31.03.2013 at 02:00:00. So you can't get a CET timezone for the second date since it is on the summer "time zone".
If you parse 31.03.2013 02:00:00 you will get
31.03.2013 02:00:00 = Sun Mar 31 03:00:00 CEST 2013
Because at 02:00:00 that day, the saving daylight time happened and it became 03:00:00.
You can check that using TimeZone.inDaylightTime(Date)
String str = "30.03.2013 06:00:00";
java.util.Date dat = sdaf.parse (str);
System.out.println (str + " = " + dat);
System.out.println("SDT : " + TimeZone.getTimeZone("CET").inDaylightTime(dat));
30.03.2013 06:00:00 = Sat Mar 30 06:00:00 CET 2013
SDT : false
str = "31.03.2013 02:00:00";
dat = sdaf.parse (str);
System.out.println (str + " = " + dat);
System.out.println("SDT : " + TimeZone.getTimeZone("CET").inDaylightTime(dat));
31.03.2013 02:00:00 = Sun Mar 31 03:00:00 CEST 2013
SDT : true
Since CET is the same as UTC+1 or GMT+1 and CEST become UTC+2 or GMT+2, when you force the date to be on GMT+1, you get the equivalent of the CET but without taking into account the SDT parameter.
Note : This is one of the reason LocalDateTime don't bother with TimeZone for most of the processing.
AxelH’s answer is correct. Thus I don’t think you really want Central European (Standard) Time for your date-time on 31st March.
I should like to make three other points:
You should never rely on any three or four letter time zone abbreviation, like CET.
If you really want Central European Time, it is possible since two African countries use CET all year, Algeria and Tunesia.
Avoid the outdated SimpleDateFormat, TimeZone and Date and use java.time, the modern Java date and time API, instead.
So my code suggestion is:
ZoneId cetAllYear = ZoneId.of("Africa/Algiers");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.uuuu HH:mm:ss");
DateTimeFormatter demoFormatter
= DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z yyyy", Locale.ROOT);
String str = "31.03.2013 05:00:00";
ZonedDateTime dateTime = LocalDateTime.parse(str, formatter).atZone(cetAllYear);
System.out.println (str + " = " + dateTime
+ " = " + dateTime.format(demoFormatter));
Output:
31.03.2013 05:00:00 = 2013-03-31T05:00+01:00[Africa/Algiers] = Sun Mar 31 05:00:00 CET 2013
The same is possible with Africa/Tunis time zone.
Avoid three letter time zone abbreviations. Central European Time is a common name for the standard time at offset +01:00 used 5 months of the year in a large number of European time zones. So in one way it’s only half a time zone, in another way it’s many, and you don’t know which one you get. And even less so when you give a date-time that falls in the summer time (DST time of the year). Very many three and four letter abbreviations are ambiguous. Instead give time zone as for example Europe/Rome or Africa/Tunis, as region/city.
Avoid SimpleDateFormat and its outdated friends. That class is notoriously troublesome. java.time is so much nicer to work with.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Central European Time on timeanddate.com.
You can use Java 8 and it is more clear and simple than this one.
DateTimeFormatter parse = DateTimeFormatter.ofPattern("dd.MM.yyyy hh:mm:ss.XXX");
LocalDate localDate = LocalDate.of(2013,3,30);
LocalTime localTime = LocalTime.of(6,0);
LocalDateTime dateTime = LocalDateTime.of(localDate, localTime);
ZonedDateTime zonedDateTime = dateTime.atZone(ZoneId.of("CET"));
System.out.println(zonedDateTime.format(parse));
Output : 30.03.2013 06:00:00.+01:00

How to use Apache DateUtils to get previous month from first day to last day with time [JAVA]?

If the input is today(June 7), then it should give me May 1 12:00 AM to May 31, 11:59 PM.
I was using Calendar but I want to use DateUtils.
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.DAY_OF_MONTH, -1);
calendar.set(Calendar.HOUR,23);
calendar.set(Calendar.MINUTE,59);
calendar.set(Calendar.SECOND,59);
System.out.println("Last date of month: " + calendar.getTime());
calendar.set(Calendar.DAY_OF_MONTH, 1);
calendar.set(Calendar.HOUR, 12);
calendar.set(Calendar.MINUTE,00);
calendar.set(Calendar.SECOND,00);
System.out.println("fir stdate of month: " + calendar.getTime());
DateUtils can do the required:
Date lastmonth = DateUtils.addMonths(new Date(), -1);
System.out.println(lastmonth);
System.out.println(DateUtils.truncate(lastmonth, Calendar.MONTH));
System.out.println(DateUtils.addMinutes(DateUtils.ceiling(lastmonth, Calendar.MONTH), -1));
Edit: Adding output
Sat May 07 23:06:05 AST 2016
Sun May 01 00:00:00 AST 2016
Tue May 31 23:59:00 AST 2016
I ended up using JodaTime. Much easier!
MutableDateTime dateTime = new MutableDateTime();
System.out.println("CurrentTime " + dateTime);
dateTime.addMonths(-1); //last Month
dateTime.setMinuteOfDay(0);
dateTime.setSecondOfMinute(0);
dateTime.setHourOfDay(12);
dateTime.setDayOfMonth(1); //first Day of last Month
System.out.println("first Day Time " + dateTime);
dateTime.setDayOfMonth(dateTime.dayOfMonth().getMaximumValue()); //set Day to last Day of that month
dateTime.setMinuteOfDay(59);
dateTime.setSecondOfMinute(59);
dateTime.setHourOfDay(23); //time set to night time 11:59:59
System.out.println("last Day Time " + dateTime);

Using GregorianCalendar to get weeks

I'm looking to utilize GregorianCalendar to do some logic based on days. Is there any way to see if 2 dates are in the same week? I've tried using get(Calendar.WEEK_OF_YEAR), and this has the two downsides of:
1) Starting on the wrong day of the week (which seems to have a potential solution in setFirstDayOfWeek, however preliminary testing has not been successful.
2) This solution does not carry over years nicely. For example - Dec 30th, 2014 and Jan 1, 2015 should be in the same week.
Is there any solution to this that doesn't require switching libraries?
OK, since you've stated there will be a time component, I'd use something similar to #MadProgrammer's answer, but without the complexity of using an entire date range. I'd have a static method something like this.
public static Date firstOfWeek(Calendar cal) {
Calendar copy = new GregorianCalendar(
cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DATE));
copy.set(Calendar.DAY_OF_WEEK, copy.getFirstDayOfWeek());
return copy.getTime();
}
This returns a Date for the first day of the week that includes a particular Calendar. You can then check whether two calendars fall in the same week like this.
if (firstOfWeek(cal1).equals(firstOfWeek(cal2))) {
...
}
You question basically boils down to determining if a given date falls within a given date range (ie a week).
The idea behind this is basically one of the two date's acts as the anchor, from which we calculate the date range (start of week to end of week) and then determine if the other date falls within that range.
So, first, we need to calculate the date range, something like...
Calendar cal = Calendar.getInstance();
cal.setTime(date1);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.clear(Calendar.MINUTE);
cal.clear(Calendar.SECOND);
cal.clear(Calendar.MILLISECOND);
cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek());
Date startOfWeek = cal.getTime();
cal.add(Calendar.DATE, 6);
cal.set(Calendar.HOUR_OF_DAY, 23);
cal.set(Calendar.MINUTE, 59);
cal.set(Calendar.SECOND, 59);
cal.set(Calendar.MILLISECOND, 999);
Date endOfWeek = cal.getTime();
Which will give us two dates, the first starting at the "start of the week" and one 6 days later (the "end of the week"). We force the time values to the extreme of the days to ensure we can capture the fall range
Next, we need to determine if the other date is equal to or after the "start of the week" and equal to or before the "end of the week", something like...
(date2.equals(startOfWeek) || date2.after(startOfWeek)) && (date2.equals(endOfWeek) || date2.before(endOfWeek));
This could then be wrapped up in a nice little method to make calling it simpler...
public static boolean isInSameWeek(Date date1, Date date2) {
Calendar cal = Calendar.getInstance();
cal.setTime(date1);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.clear(Calendar.MINUTE);
cal.clear(Calendar.SECOND);
cal.clear(Calendar.MILLISECOND);
cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek());
Date startOfWeek = cal.getTime();
cal.add(Calendar.DATE, 6);
cal.set(Calendar.HOUR_OF_DAY, 23);
cal.set(Calendar.MINUTE, 59);
cal.set(Calendar.SECOND, 59);
cal.set(Calendar.MILLISECOND, 999);
Date endOfWeek = cal.getTime();
System.out.println("Week starts at : " + startOfWeek);
System.out.println(" Week ends at : " + endOfWeek);
return (date2.equals(startOfWeek) || date2.after(startOfWeek)) && (date2.equals(endOfWeek) || date2.before(endOfWeek));
}
And then we can test it...
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
try {
Date date1 = sdf.parse("30/12/2014");
Date date2 = sdf.parse("1/1/2015");
System.out.println("Is in same week " + date1 + "/" + date2 + " = " + isInSameWeek(date1, date2));
System.out.println("");
date1 = sdf.parse("27/12/2014");
System.out.println("Is in same week " + date1 + "/" + date2 + " = " + isInSameWeek(date1, date2));
} catch (ParseException exp) {
exp.printStackTrace();
}
Which outputs something like...
Week starts at : Sun Dec 28 00:00:00 EST 2014
Week ends at : Sat Jan 03 23:59:59 EST 2015
Is in same week Tue Dec 30 00:00:00 EST 2014/Thu Jan 01 00:00:00 EST 2015 = true
Week starts at : Sun Dec 21 00:00:00 EST 2014
Week ends at : Sat Dec 27 23:59:59 EST 2014
Is in same week Sat Dec 27 00:00:00 EST 2014/Thu Jan 01 00:00:00 EST 2015 = false

Java: Date/Time from Database to milliseconds, hour disappearing

I am having an issue with Dates and timezones.
I have a MySQL InnoDB database which holds two fields DATE(yyyy-MM-dd) and TIME(HH:mm:ss). These are known as to be UTC (0 GMT). My computer is based in CET (+1 GMT).
• dateObject is the result from this resultSet.getTime("date_field") (java.sql.Date)
• timeObject is a result from this resultSet.getDate("time_field") (java.sql.Time)
In the database DATE is stored as 2014-02-22 and TIME 15:00
System.out.println("Untouched "+dateObject+" "+timeObject);
long date = dateObject.getTime();
long time = timeObject.getTime();
System.out.println("Touched "+new Date(date+time));
Results in the following output:
Untouched 2014-02-22 15:00:00
Touched Sat Feb 22 14:00:00 CET 2014
Why is one hour being skipped off the Touched output? I was expecting the following:
Untouched 2014-02-22 15:00:00
Touched Sat Feb 22 15:00:00 CET 2014
To rumble things up I have tried with the following also:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(new Date(date+time)));
And result:
2014-02-22 14:00:00
All in all. I am expecting GMT+1 to show 16:00(local) and GMT+0 to display 15:00
I think I did answer ma question (Remember timeObject in the db is 15:00:00 at UTC):
TimeZone tz = TimeZone.getTimeZone("Gmt0");
SimpleDateFormat sdfFull = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdfFull.setTimeZone(tz);
Date updateDate = sdfFull.parse(dateObject.toString()+" "+timeObject.toString());
System.out.println(updateDate);
Results in what I was hoping for:
Sat Feb 22 16:00:00 CET 2014
The reason is similar to this SO-answer. But note following details about toString().
java.util.Date.toString() => output dependent on your system time zone
in format pattern "EEE MMM dd HH:mm:ss zzz yyyy"
java.sql.Date.toString() => output in format "yyyy-MM-dd" (your dateObject)
java.sql.Time.toString() => output in format "HH:mm:ss" (your timeObject)
The sql representations are not dependent on time zone. So you compare apples and peaches.
Supplementary remark:
I have invested more in testing and found:
java.sql.Date dateObj = new java.sql.Date(2014 - 1900, Calendar.FEBRUARY, 22);
Time timeObj = new Time(15, 0, 0);
Time midnight = new Time(0, 0, 0);
Date d = new Date(dateObj.getTime() + timeObj.getTime());
System.out.println("dateObj: " + dateObj + "/" + dateObj.getTime());
// dateObj: 2014-02-22/1393023600000, one hour less than a full day because of UTC-long
System.out.println("timeObj: " + timeObj + "/" + timeObj.getTime());
// timeObj: 15:00:00/50400000 => one hour less as UTC-long
System.out.println("midnight: " + midnight + "/" + midnight.getTime());
// midnight: 00:00:00/-3600000 => one hour less, negative!
System.out.println(new Date(dateObj.getTime())); // Sat Feb 22 00:00:00 CET 2014
System.out.println(new Date(timeObj.getTime())); // Thu Jan 01 15:00:00 CET 1970
System.out.println(d); // Sat Feb 22 14:00:00 CET 2014
So I strongly suspect following effect: Both dateObject and timeObject are been calculated your system time zone, therefore their utc-long values show both one hour less - the time zone offset. If you combine both in one Date-object by just summarizing up then one of both deltas gets lost because one single date object cannot take in account two offsets.
Conclusion: You tried to combine date and time by summarize their utc-longs, but this is in general a faulty approach. Date plus Date is not Date, but undefined! In domain-specific language you can only add a duration/period to a date/time. So a solution having a midnight object could be:
Date d = new Date(dateObj.getTime() + timeObj.getTime() - midnight.getTime());
System.out.println(d); // Sat Feb 22 15:00:00 CET 2014, correct - what you wanted

Calendar issue in Adding month +1 to to calendar month in Android

I am using the following code
Calendar cal = Calendar.getInstance();
System.out.println("Before "+cal.getTime());
cal.set(Calendar.MONTH, 01);
System.out.println("After "+cal.getTime());
the output is
Before Thu Jan 31 10:07:34 IST 2013
After Sun Mar 03 10:07:34 IST 2013
for adding +1 to jan is giving mar month. may be it returning correct output if we add 30 days to present date. but i want to show feb month. can any body help me please..
you can see the +1 to set field is adding 30 days date different to your dates(observed from your output.)
if you want months then use the code
Calendar cal = Calendar.getInstance();
System.out.println("Before "+cal.getTime()); //Before Thu Jan 31 10:16:23 IST 2013
cal.add(Calendar.MONTH, 1);
System.out.println("After "+cal.getTime()); //After Thu Feb 28 10:16:23 IST 2013
You have to use add() like,
cal.add(Calendar.MONTH, 1);
OUTPUT ->
Before Thu Jan 31 10:15:04 IST 2013
After Thu Feb 28 10:15:04 IST 2013
This kind of date-time work is easier using either:
Joda-Time 2.3 library
Popular replacement for the java.util.Date & .Calendar classes bundled with Java
Open source
Free of cost
Actively maintained (as of 2014-02)
java.time package
New in Java 8
Inspired by Joda-Time, but re-architected
Defined by JSR 310
Tutorial available
Example Code
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" ); // Or, DateTimeZone.UTC
DateTime dateTime = new DateTime( timeZone );
DateTime monthAgo = dateTime.plusMonths( -1 ); // Smartly handles various month lengths, leap year, and so on.
DateTime monthLater = dateTime.plusMonths( 1 );
Dump to console…
System.out.println( "dateTime: " + dateTime );
System.out.println( "monthAgo: " + monthAgo );
System.out.println( "monthAgo start of day: " + monthAgo.withTimeAtStartOfDay() );
System.out.println( "monthLater: " + monthLater );
When run…
dateTime: 2014-02-24T01:53:22.386+01:00
monthAgo: 2014-01-24T01:53:22.386+01:00
monthAgo start of day: 2014-01-24T00:00:00.000+01:00
monthLater: 2014-03-24T01:53:22.386+01:00
cal.set(Calendar.MONTH, cal.get( Calendar.MONTH ) + 1 );
The reason it shows Mar 3 anyway, is because it apparently adds 30 days, which is Feb 31st which does not exist, so it goes to Mar 3.
If you wanted the last day of the next month instead, you would do something like this:
int month = cal.get( Calendar.MONTH );
cal.set(Calendar.MONTH, cal.get(Calendar.MONTH) + 1);
if( cal.get( month ) > month + 1 ) {
cal.set( Calendar.MONTH, month + 1 );
cal.set( Calendar.DAY, /* here comes your day amount finding algorithm */ );
}

Categories

Resources