Reset time part of Calendar instance in Java - java

There is Java code,which is ran on 2 different environments and inserts records with JdbcTemplate to DB.
Results of its running are different for both envs. Particularly,for Date fields.
On first environment(Oracle XE) it produces record:
"12/03/2010";191094;"71697211000";3229;880323202;NULL;0;1;0;NULL;0;NULL
Second environment(Oracle non XE):
"12/03/2010 12:00:00";191094;"71697211000";3229;880323202;NULL;0;1;0;NULL;0;NULL
NLS_DATE_FORMAT(if it's crucial) for first env is DD-MON-RR,
for second env is DD-MON-RRRR
The question is,what Oracle settings may affect,that second env Date format is another?

should set following Calendar properties in Java code:
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, cal.getActualMinimum(Calendar.HOUR_OF_DAY));
cal.set(Calendar.MINUTE, cal.getActualMinimum(Calendar.MINUTE));
cal.set(Calendar.SECOND, cal.getActualMinimum(Calendar.SECOND));
cal.set(Calendar.MILLISECOND, cal.getActualMinimum(Calendar.MILLISECOND));
instead of:
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);

According to the documentation, HH refers to a 12-hour time. The 12 in the time you're retrieving is 12 midnight. What you want is HH24, which ges you a 24-hour time, starting at 00 for midnight.

If you don't want to show the time part, don't include a format string which includes the time part ("HH:MI:SS").
You've reset the time part to midnight, basically... there's no way of differentiating between a Calendar or Date set to exactly midnight and a Calendar or Date "without" a time part - because there's no such concept as a Calendar/Date with only a date part.
Now you may be able to have that in the database, depending on what types are available to you - but java.util.Date and java.util.Calendar always represent points in time, not just dates.
The reason it's showing 12 instead of 00 is because you're using "HH" instead of "HH24", as per lacqui's answer. I assume you don't really want to see the time at all though, given that you'll have reset it to midnight...

I'd recommend you extend one of the Calendar classes like this:
public class CalendarDateOnly extends GregorianCalendar {
public static Calendar getInstance() {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, cal.getActualMinimum(Calendar.HOUR_OF_DAY));
cal.set(Calendar.MINUTE, cal.getActualMinimum(Calendar.MINUTE));
cal.set(Calendar.SECOND, cal.getActualMinimum(Calendar.SECOND));
cal.set(Calendar.MILLISECOND, cal.getActualMinimum(Calendar.MILLISECOND));
return cal;
}
}
Instantiate in this way:
Calendar june30 = CalendarDateOnly.getInstance();
june30.set(2000, Calendar.JUNE, 30);

/*
* Date : 2015-07-09
* Author : Bhuwan Prasad Upadhyay
*/
package com.developerbhuwan.date.utils;
import java.util.Calendar;
import java.util.Date;
/**
*
* #author developerbhuwan
*/
public class CalenderUtils {
public static Calendar getNewCalendarInstance() {
Calendar calendar = Calendar.getInstance();
return resetCalender(calendar);
}
public static Date resetDate(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
return resetCalender(calendar).getTime();
}
public static Calendar resetCalender(Calendar calendar) {
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar;
}
public static void setTimeInCalendar(Calendar calendar, Date date) {
calendar.setTime(resetDate(date));
}
}

Related

Wrong value of Days between two Dates

I'm trying to count the days between two dates but I can't get a right result.
I did the same that someone described to me.
My result should be an int or long. For this example I would expext 11 but 10 is also fine.
That's the code:
String startDate = "2018-03-25";
String endDate = "2018-04-05";
Date startDate1 = stringToDate(startDate);
Date endDate1 = stringToDate(endDate);
long ab = daysBetween(startDate1, endDate1);
String ab1 = String.valueOf(ab);
And that's the methods:
public static long daysBetween(Date startDate, Date endDate) {
Calendar sDate = getDatePart(startDate);
Calendar eDate = getDatePart(endDate);
long daysBetween = 0;
while (sDate.before(eDate)) {
sDate.add(Calendar.DAY_OF_MONTH, 1);
daysBetween++;
}
return daysBetween;
}
public Date stringToDate(String stringDatum) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
try {
Date date = format.parse(stringDatum);
return date;
}
catch (ParseException e) {
e.printStackTrace();
}
return null;
}
public static Calendar getDatePart(Date date){
Calendar cal = Calendar.getInstance(); // get calendar instance
cal.setTime(date);
cal.set(Calendar.HOUR_OF_DAY, 0); // set hour to midnight
cal.set(Calendar.MINUTE, 0); // set minute in hour
cal.set(Calendar.SECOND, 0); // set second in minute
cal.set(Calendar.MILLISECOND, 0); // set millisecond in second
return cal; // return the date part
}
java.util.Date, Calendar and SimpleDateFormat are part of a terrible API. They make the job of date/time handling harder than it already is.
Make yourself a favor and use a decent date/time library: https://github.com/JakeWharton/ThreeTenABP - here's a nice tutorial on how to use it - How to use ThreeTenABP in Android Project
With this API, it's so easy to do what you want:
LocalDate startDate = LocalDate.parse("2018-03-25");
LocalDate endDate = LocalDate.parse("2018-04-05");
long daysBetween = ChronoUnit.DAYS.between(startDate, endDate); // 11
I've chosen to use LocalDate based on your code: the inputs have only day, month and year, and you're setting the hour/minute/seconds to zero, so I understand that you don't care about the time of the day to calculate the difference - which makes LocalDate the best choice.
Date and Calendar represent a specific point in time, and Calendar also uses a timezone, so Daylight Saving changes might affect the results, depending on the device's default timezone. Using a LocalDate avoids this problem, because this class doesn't have a timezone.
But anyway, I've tested your code and also got 11 as result, so it's not clear what problems you're facing.
private static long daysBetween(Date date1, Date date2){
return (date2.getTime() - date1.getTime()) / (60*60*24*1000);
}

A function to convert minute since midnight to am/pm time

Is there an existing android or java or joda-time function for converting minutes since midnight to time? I know how to do it for a 24 hour period without the am/pm bit. But I need to have the am/pm for some users.
This is for an android app. So the added benefit of using a standard function is that it will conform to the general preference of the user.
I suppose I can roll out my (buggy) own if such does not exist.
You could use Calendar and SimpleDateFormat to get that. Something like,
static DateFormat _sdf = new SimpleDateFormat("hh:mm a");
static String minutesSinceMidnight(int minutes) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.AM_PM, Calendar.AM);
cal.set(Calendar.HOUR, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
cal.add(Calendar.MINUTE, minutes);
return _sdf.format(cal.getTime());
}

Inconsistent behavior with setting Java calendar object to midnight

I have a Java program where I need to set a Calendar object to be midnight, so I followed the instructions from another posting on how to create a Java Date object of midnight today and midnight tomorrow, where you set the fields to be 0, like so:
calStart.set(Calendar.HOUR_OF_DAY, 0);
calStart.set(Calendar.MINUTE, 0);
calStart.set(Calendar.SECOND, 0);
calStart.set(Calendar.MILLISECOND, 0);
However, I am getting inconsistent results using Java 1.7.0_51. (Please no suggestions on using Jodatime, as I would like to use the base library only.)
Here is my test program:
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;
public class MidnightTester {
public static void runTestMidnight1() {
System.out.printf("runTestMidnight1() called\n");
TimeZone tz = TimeZone.getTimeZone("UTC");
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(1437004800000L);
cal.setTimeZone(tz);
System.out.printf("Original timestamp:\n");
printCalendarWithTimeZone(cal, tz);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
System.out.printf("Timestamp after setting to midnight:\n");
printCalendarWithTimeZone(cal, tz);
}
public static void runTestMidnight2() {
System.out.printf("runTestMidnight2() called\n");
TimeZone tz = TimeZone.getTimeZone("UTC");
Calendar cal = Calendar.getInstance();
cal.setTimeZone(tz);
cal.setTimeInMillis(1437004800000L);
System.out.printf("Original timestamp:\n");
printCalendarWithTimeZone(cal, tz);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
System.out.printf("Timestamp after setting to midnight:\n");
printCalendarWithTimeZone(cal, tz);
}
public static void printCalendarWithTimeZone(Calendar cal, TimeZone tz) {
SimpleDateFormat sdf = new SimpleDateFormat("EEEE, MMMM dd, yyyy, hh:mm:ss aaa");
sdf.setTimeZone(tz);
System.out.printf("%d= %s\n", cal.getTimeInMillis(), sdf.format(cal.getTime()));
}
public static void main(String argv[]) {
runTestMidnight1();
runTestMidnight2();
}
}
Here is the output:
runTestMidnight1() called
Original timestamp:
1437004800000= Thursday, July 16, 2015, 12:00:00 AM
Timestamp after setting to midnight:
1436918400000= Wednesday, July 15, 2015, 12:00:00 AM
runTestMidnight2() called
Original timestamp:
1437004800000= Thursday, July 16, 2015, 12:00:00 AM
Timestamp after setting to midnight:
1437004800000= Thursday, July 16, 2015, 12:00:00 AM
As you can see, in runTestMidnight1(), the day changes from July 16 to July 15 after setting the time to midnight! I don't get that.
What's more weird is that in runTestMidnight2(), I swap only two lines, and the day correctly stays the same on July 16.
cal.setTimeZone(tz);
cal.setTimeInMillis(1437004800000L);
I am in America/Pacific time, in case that matters.
Can someone help me understand what's going on?
EDIT: Better Explanation
When we call setTimeInMillis(), the passed long values is assumed to be in UTC. and it calculates the time in calendar object time using user's timezone or if any timezone already available with Calendar object.
If there is no timezone passed then user's timezone gets set on calendar object. So the value '1437004800000L' considered to be in PST timezone and time gets calculated with PST timezone.
Calling setTimeZone() after setting time in millis is changing the timezone in Calendar object. So the calendar object time gets moved to UTC. This is the case of runTestMidnight1(). And that's why we see a shift in date because original time was in PST.
While in second method, the timezone is first set by setTimeZone() to UTC. So the time value is '1437004800000L' and considered timezone is UTC and calculated time would be in UTC. And you gets UTC time only.
And this problem gets reproduced only if user is in timezone which behind the UTC timezone.
Hope it clarifies.

Date shifts one day off on click of save

They have used GWT to create a form which contains date pickers when user submits the form, dates selected shifts one day back. e.g. if i select 21/06/2015 it shifts to 20/06/2015. This is happening when users time zone is different from server time zone. When i debug it, i found that it shifts one day back while converting date to calendar because Date is client zone's Date and Date to Calendar conversion is happening in server side for sending it to marshalling(before sending request to rest service API for saving).
Following code is used for converting date to calendar.
Calendar cal = Calendar.getInstance();
int offset = date.getTimezoneOffset();
logger.info("Calendar Instance - " + cal);
cal.setTime(date);
logger.info("Calendar Instance after setting date - " + cal);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
logger.info("Calendar Instance after setting zeros - " + cal);
return cal;
In last log it displays one day less than actual date.
it works fine if i remove the following code.
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
for IST and PST but not to other timezones.
Please help.

How do I use calendar and timezone

I´m doing an example using Date and Calendar classes, this is my code:
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:00Z");
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 2013);
cal.set(Calendar.MONTH, Calendar.SEPTEMBER);
cal.set(Calendar.DATE, 1);
cal.set(Calendar.HOUR_OF_DAY, 12);
cal.set(Calendar.MINUTE, 15);
Date date = cal.getTime();
TimeZone tz = TimeZone.getTimeZone("IST");
dateFormat.setTimeZone(tz);
String actual = dateFormat.format(date);
System.out.println(actual);
I would expect as result 2013-09-01 12:15:00+0530 but the value return is 2013-09-01 15:45:00+0530 and I don´t know why.
I'm going to move a few things around
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:00Z");
TimeZone tz = TimeZone.getTimeZone("IST"); // <-- Move this here.
Calendar cal = Calendar.getInstance();
cal.setTimeZone(tz); // <-- So we can use it here.
cal.set(Calendar.YEAR, 2013);
cal.set(Calendar.MONTH, Calendar.SEPTEMBER);
cal.set(Calendar.DATE, 1);
cal.set(Calendar.HOUR_OF_DAY, 12);
cal.set(Calendar.MINUTE, 15);
Date date = cal.getTime();
dateFormat.setTimeZone(tz); // <-- And here.
Then your code produces your expected output. That is
2013-09-01 12:15:00+0530
package stackoverflow;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class StackOverflow {
public static void main(String[] args) {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:00Z");
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 2013);
cal.set(Calendar.MONTH, Calendar.SEPTEMBER);
cal.set(Calendar.DATE, 1);
cal.set(Calendar.HOUR_OF_DAY, 12);
cal.set(Calendar.MINUTE, 15);
Date date = cal.getTime();
// TimeZone tz = TimeZone.getTimeZone("IST");
// dateFormat.setTimeZone(tz);
String actual = dateFormat.format(date);
System.out.println(actual);
}
}
gives:
run:
2013-09-01 12:15:00-0700
BUILD SUCCESSFUL (total time: 1 second)
which is, I think, along the lines of what you want. The timezone is changing the time.
The Calendar instance that you created must also be told about the timezone, i.e.:
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("IST"));
Otherwise, it would take the timezone of your machine.
DateFormat and Calendar depend on timezone.
While creating date and formatting use specific timezone.
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:00Z");
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("IST"));
cal.set(Calendar.YEAR, 2013);
cal.set(Calendar.MONTH, Calendar.SEPTEMBER);
cal.set(Calendar.DATE, 1);
cal.set(Calendar.HOUR_OF_DAY, 12);
cal.set(Calendar.MINUTE, 15);
Date date = cal.getTime();
dateFormat.setTimeZone(TimeZone.getTimeZone("IST"));
String actual = dateFormat.format(date);
System.out.println(actual);
The Joda-Time abides.
I suspect your direct problem is that you instantiated the Calendar instance using your own environment's time zone, then switched the time zone on that already existing object. That seems to be what the other answers point to.
A side problem is using a three-letter code for identifying a time zone. They are not standard and have many duplicates. In your case, did you mean IST to be India Standard Time or Irish Standard Time? Use a named time zone instead.
But your bigger problem is using the java.util.Date/Calendar classes at all. They are notoriously bad.
Joda-Time
Here's the same kind of code but done properly in Joda-Time 2.3.
Note in particular that I am not setting a time zone on the formatter. The DateTime object knows its own time zone.
// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// import org.joda.time.*;
// import org.joda.time.format.*;
DateTimeZone kolkataTimeZone = DateTimeZone.forID( "Asia/Kolkata" );
DateTime kolkataDateTime = new DateTime( 2013, DateTimeConstants.SEPTEMBER, 1, 12, 15, 0, kolkataTimeZone );
System.out.println( "kolkataDateTime: " + kolkataDateTime );
// If you really cannot stand the 'T'.
DateTimeFormatter formatter = DateTimeFormat.forPattern( "yyyy-MM-dd' 'HH:mm:ssZ" );
System.out.println( "kolkataDateTime sans 'T': " + formatter.print( kolkataDateTime ) );
When run…
kolkataDateTime: 2013-09-01T12:15:00.000+05:30
kolkataDateTime sans 'T': 2013-09-01 12:15:00+0530

Categories