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.
Related
This question already has answers here:
Java get UTC time
(5 answers)
Closed 7 years ago.
I have a Calendar object manipulated according to my needs, but converting it to Instant is not giving me the correct result:
Calendar cal = Calendar.getInstance(); // creates calendar
cal.setTime(inputFiledate); // sets calendar time/date --> inputFiledate is 29-12-2015
cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(inputFileHour)); -->inputFileHour is 5
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
cal.add(Calendar.HOUR_OF_DAY,3); // adds hours that is now time is 29-12-2015 08:00:00
System.out.println("Date after manipulation "+cal.getTime()); -->Displays
TimeZone tz = TimeZone.getTimeZone("UTC");
// set the time zone with the given time zone value
// and print it
cal.setTimeZone(tz);
// Date date = cal.getTime(); // returns new date object, one hour in the future
Date d= cal.getTime();
System.out.println("DAte to Instant "+ d.toInstant());
System.out.println(" Calendar to Instant "+cal.toInstant());
System.out.println("Date after manipulation2 "+cal.getTime());
This is the output:
Date after manipulation Tue Dec 29 08:00:00 IST 2015
DAte to Instant 2015-12-29T02:30:00Z
Calendar to Instant 2015-12-29T02:30:00Z
Date after manipulation2 Tue Dec 29 08:00:00 IST 2015
In need to convert this Calendar object to instant but it is giving incorrect result 2015-12-29T02:30:00Z
where as the output should be 2015-12-29T08:00:00Z
Where m I going wrong?
Also tried with Zoned datetime, with Timezone, in vain.
Date doesn't have a time zone. From the time difference I assume you are using Indian Time (-5:30) It is just the time relative to epoch which is different in each time zone.
I suggest you do the calculation using ZonedDateTime instead of trying to convert from a Calendar.
According to MSDN, System.DateTime.Ticks "represents the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001 (0:00:00 UTC on January 1, 0001, in the Gregorian calendar)".
There's a internal field in DateTime, UnixEpoch, with the value 621355968000000000L which should correspond to the Unix Epoch (midnight, January 1, 1970 UTC). (We can get the same value from new DateTime(1970,1,1,0,0,0,0,System.DateTimeKind.Utc);.)
I'm trying to create a Date in Java based on a C# ticks value:
Here's a simple Java example to reproduce the problem:
//C# System.DateTime.UnixEpoch = 621355968000000000;
//Java code:
//before Unix Epoch, in milliseconds
Date date = new Date(-621355968000000000L / 10000);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS Z");
df.setTimeZone(TimeZone.getTimeZone("UTC"));
df.format(date); // 0001-01-03 00:00:00.000 +0000
Is there a kind of gap in Gregorian calendar, which is taken into account only by one of platforms?
It seems Java Date uses the Julian Calendar for dates when that calendar was used while C#, in this case, uses Gregorian Calendar back before there was one. By default Joda-Time also uses the Gregorian Calendar back in time.
This seems to work but there's probably a better way.
DateTime dt = new DateTime(-621355968000000000L / 10000);
GregorianCalendar gc = new GregorianCalendar();
gc.set(GregorianCalendar.YEAR, dt.getYear());
gc.set(GregorianCalendar.MONTH, dt.getMonthOfYear() - 1);
gc.set(GregorianCalendar.DAY_OF_MONTH, dt.getDayOfMonth());
gc.set(Calendar.HOUR_OF_DAY, 0);
gc.set(Calendar.MINUTE, 0);
gc.set(Calendar.SECOND, 0);
gc.set(Calendar.MILLISECOND, 0);
Date date = gc.getTime();
I have written two functions - today() and todayUTC() - as:
public static Date today() {
Calendar cal = Calendar.getInstance();
return cal.getTime();
}
public static Date todayUTC() {
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
return cal.getTime();
}
But when I print the results of these functions using:
public void todayTest() {
Date date1 = OOTBFunctions.today();
System.out.println("today: "+date1);
Date dateUTC1 = OOTBFunctions.todayUTC();
System.out.println("todayUTC: "+dateUTC1);
}
I saw that both statements print the same value i.e.
today: Thu Aug 30 14:48:56 PDT 2012
todayUTC: Thu Aug 30 14:48:56 PDT 2012
Can anybody suggest what am I missing in UTC function that I am getting local timezone date.
Java uses the default Locale while printing and that is why you see that behavior. Use code like below to format and print it in the locale/format you want. Remember
When you create a Date object, it is always in UTC.
Display the date in the Locale of the user.
Store the date in UTC.
Code
final SimpleDateFormat sdf = new SimpleDateFormat("the format you want");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
final String utcTime = sdf.format(new Date());
You doesn't need both today() and todayUTC() methods. keep and like below
public static Date nowInUTC()
{
return new Date();
}
You doesn't need to test anything.
Both of your methods will return the same value - a Date object doesn't have any notion of a time zone (unlike a Calendar). A Date just represents an instant in time, stored internally as the number of milliseconds since midnight January 1st 1970, UTC. Effectively, you've got two methods which are equivalent to:
return new Date(System.currentTimeMillis());
Date.toString() always uses the system default time zone.
If you want to maintain a date/time with a time zone, consider just using Calendar. If you want to format a particular instant in time in a time zone, just use SimpleDateFormat having set the time zone.
Ideally, change to use Joda Time instead of Date or Calendar though - it's a much cleaner API.
I have a time input in the following format from a RSS feed:
Wed Jun 13 17:05:44 +0000 2012
and I need output as Wed Jun 13, 2012 22:35:44
The source time will be always in GMT, and the required output time will be in the device time zone(it may be GMT+5:30 or GMT-2:00 or any).
So firstly I have an calendar instance with GMT, as follows.
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
Then modified the calendar like following using StringTokenizer on input time.
calendar.set(Calendar.DAY_OF_MONTH, date);
calendar.set(Calendar.MONTH, month);
.
.
etc.
Next I have the following code:
calendar.setTimeZone(TimeZone.getDefault());
Basically the above code changes a calendar into device time zone.
Now the matter is the above code is working fine in normal environment, but not working in Android.
Any solution? Please help.
First you required DateFormat to parse string value in Date object and then you can set Timezone in Date as well as you can make Calendar object with help of Date that calendar object will be your device timezone instance.
Below code is working at my side
String input_format = "EEE MMMMM dd HH:mm:ss Z yyyy";
String input_value="Wed Jun 13 17:05:44 +0000 2012";
Date date=null;
SimpleDateFormat sdf = new SimpleDateFormat(input_format);
try {
date = sdf.parse(input_value);
} catch (ParseException e) {
e.printStackTrace();
}
Calendar calendar = sdf.getCalendar();
calendar.setTime(date);
if i understand it right, you just want to set the timezome
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setTimeZone("Europe/Paris");
this for example set the timezone to Paris
I tried to do set date value to a PreparedStatement with default value but the value is sometimes returned as a JulianValue. For example (Assume spanBegin and spanEnd are null)
Calendar cal = new GregorianCalendar();
if (spanBegin == null) {
cal.set(0000, Calendar.JANUARY, 1);
spanBegin = cal.getTime();
}
if (spanEnd == null)
{
cal.set(9999, Calendar.DECEMBER, 31);
spanEnd = cal.getTime();
}
On line number 3, since the date January 1, 0000 is scoped by a Julian Calendar, the CDate becomes a Julian Calendar. However, the next Date even if it is in the year 9999, its CDate becomes a Julian Calendar still. I had to create another instance of Gregorian Calendar to fix the issue.
Calendar cal = new GregorianCalendar();
if (spanBegin == null) {
cal.set(0000, Calendar.JANUARY, 1);
spanBegin = cal.getTime();
}
Calendar cal = new GregorianCalendar();
if (spanEnd == null)
{
cal.set(9999, Calendar.DECEMBER, 31);
spanEnd = cal.getTime();
}
The question is, is the this an expected behavior or a bug on the date object? Actually using GregorianCalendar.getInstance() shows that the cdate is sometimes set to JulianCalendar.
There was no Gregorian Calendar until 1582. The Julian calendar was in use all over Europe, until minor problems started to appear caused by the fact the solar year is not exactly 365.25 days, but a little less than that. In order to fix things, pope Gregory XIII ordered to change the calendar to what we know today - every year that divides by 100 is not a leap year, unless it divides by 400. In October 1582 there was the transition - the day after 4 Oct was 15 Oct. This means that until October 1582, the Gregorian and Julian Calendars are the same. You can read more about it here
This is why dates prior to Oct 1582 are converted to use the Julian system. According to the API If you actually need to represent an historical event (which seems not to by the case here) you can do it only from 1st march, 4AD
What version of Java are you using and on what OS? Do you really need to store dates in the years 0 and 9999, or are you just using these as "negative infinity" and "positive infinity" values? How exactly do you see that the calendar is a Julian calendar?
I tried this:
Calendar cal = Calendar.getInstance();
cal.set(0, Calendar.JANUARY, 1);
Date d1 = cal.getTime();
cal.set(9999, Calendar.DECEMBER, 31);
Date d2 = cal.getTime();
System.out.println(d1);
System.out.println(d2);
Output (on Windows XP, using Sun Java 1.6.0_16):
Thu Jan 01 09:53:56 CET 1 java.util.Date
Tue Dec 31 09:53:56 CET 9999 java.util.Date
It changes the year 0 to the year 1. Changing the code to use a second Calendar object for the second date:
Calendar cal = Calendar.getInstance();
cal.set(0, Calendar.JANUARY, 1);
Date d1 = cal.getTime();
Calendar cal2 = Calendar.getInstance();
cal2.set(9999, Calendar.DECEMBER, 31);
Date d2 = cal2.getTime();
System.out.println(d1);
System.out.println(d2);
This does not change anything to the output or the content of the two Date objects.
Note: Beware that integer literals that start with a 0, such as 0000 in your code, will be interpreted as octal numbers by the Java compiler. That doesn't matter in this case because the number is 0, but you should not prepend integer literals with zeroes if you don't mean them as octal numbers.
Thhere is no year 0 in Julian calendar. It goes from 1 BC to 1 AD.