Adding days with java.util.Calendar gives strange results - java

Using java.util.Calendar to add a single day to a Date, and SimpleDateFormat to display the result, sometimes seems to lose a day (generally in March) and sometimes skips a day (in November).
The program below, with output, illustrates the issue. Notice that I'm just adding one day at a time, then skipping a few months and adding a few more days. You'll see that 2008-03-09 gets printed twice, but 2008-11-02 is skipped. The same thing happens in other years, but on different days. I had to experiment to find the days that cause the problem.
If I don't set the timezone to UTC in the SimpleDateFormat then the problem does not occur. I ran this on a machine in the US Central Time Zone.
This certainly looks like a bug in Calendar or SimpleDateFormat, but I have not been able to find it documented anywhere. Anybody have an explanation of what is happening here?
The program:
package mab;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class CalendarHiccup2 {
public static void main(String[] args) {
addDays("2008-03-08");
addDays("2009-03-07");
addDays("2010-03-13");
}
public static void addDays(String dateString) {
System.out.println("Got dateString: " + dateString);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
Calendar calendar = Calendar.getInstance();
try {
calendar.setTime(sdf.parse(dateString));
Date day1 = calendar.getTime();
System.out.println(" day1 = " + sdf.format(day1));
calendar.add(java.util.Calendar.DAY_OF_MONTH, 1);
Date day2 = calendar.getTime();
System.out.println(" day2 = " + sdf.format(day2));
calendar.add(java.util.Calendar.DAY_OF_MONTH, 1);
Date day3 = calendar.getTime();
System.out.println(" day3 = " + sdf.format(day3));
calendar.add(java.util.Calendar.DAY_OF_MONTH, 1);
Date day4 = calendar.getTime();
System.out.println(" day4 = " + sdf.format(day4));
// Skipping a few days ahead:
calendar.add(java.util.Calendar.DAY_OF_MONTH, 235);
Date day5 = calendar.getTime();
System.out.println(" day5 = " + sdf.format(day5));
calendar.add(java.util.Calendar.DAY_OF_MONTH, 1);
Date day6 = calendar.getTime();
System.out.println(" day6 = " + sdf.format(day6));
calendar.add(java.util.Calendar.DAY_OF_MONTH, 1);
Date day7 = calendar.getTime();
System.out.println(" day7 = " + sdf.format(day7));
calendar.add(java.util.Calendar.DAY_OF_MONTH, 1);
Date day8 = calendar.getTime();
System.out.println(" day8 = " + sdf.format(day8));
} catch (Exception e) {
}
}
}
The output:
Got dateString: 2008-03-08
day1 = 2008-03-08
day2 = 2008-03-09
day3 = 2008-03-09
day4 = 2008-03-10
day5 = 2008-10-31
day6 = 2008-11-01
day7 = 2008-11-03
day8 = 2008-11-04
Got dateString: 2009-03-07
day1 = 2009-03-07
day2 = 2009-03-08
day3 = 2009-03-08
day4 = 2009-03-09
day5 = 2009-10-30
day6 = 2009-10-31
day7 = 2009-11-02
day8 = 2009-11-03
Got dateString: 2010-03-13
day1 = 2010-03-13
day2 = 2010-03-14
day3 = 2010-03-14
day4 = 2010-03-15
day5 = 2010-11-05
day6 = 2010-11-06
day7 = 2010-11-08
day8 = 2010-11-09

This is caused by the daylight saving time and is completely correct.
The time (on north hemisphere) is advanced one hour typically in March and moved back in November.

It looks more like a day light saving time issue, which changes in Mar and Nov. Can you try setting the time element to 00:00:00? If you do,
addDays("2008-03-08 00:00:00");
addDays("2009-03-07 00:00:00");
addDays("2010-03-13 00:00:00");
and change the format to,
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
you'll see the difference it makes in the time elements.

When you have these kind of issues you have to print the Calendar and Date instances to figure out what's going on.
The following:
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
changes the time of your Calendar depending on your JVM local time (and timezone). Calendar.getInstance(); creates a Calendar in your JVM local time, when you do calendar.setTime(sdf.parse(".....")) that sets the time in UTC (given how you created the sdf!). Depending on the DoY (and the Year as well!) that can make you pass the midnight and when you print your Date with the yyyy-MM-dd format you see the one day difference.
Print the full Calendar and full Date and you'll figure out what's going on!

Daylight Saving Time
The answer by Tomasz Nurkiewicz is correct, the problem is Daylight Saving Time (DST).
the local time changes at 02:00 local standard time to 03:00 local daylight time on the second Sunday in March and returns at 02:00 local daylight time to 01:00 local standard time on the first Sunday in November.
See Wikipedia on Central Time Zone
Joda-Time
The Joda-Time library makes this kind of work much easier.
A DateTime in Joda-Time knows its own time zone. To use UTC/GMT (no time offset), pass the built-in constant DateTimeZone.UTC.
To print out only the date portion of a date-time, use a DateTimeFormatter.
// © 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.*;
String dateString = "2008-03-08";
// withTimeAtStartOfDay() is probably superfluous in this example, but I like that it self-documents our focus on the day rather than a particular time of day.
DateTime dateTime = new DateTime( dateString, DateTimeZone.UTC ).withTimeAtStartOfDay();
DateTime dateTimePlus1 = dateTime.plusDays( 1 ).withTimeAtStartOfDay();
DateTime dateTimePlus2 = dateTime.plusDays( 2 ).withTimeAtStartOfDay();
DateTime dateTimePlus3 = dateTime.plusDays( 3 ).withTimeAtStartOfDay();
Dump to console…
System.out.println("dateTime: " + dateTime );
System.out.println("dateTime (date portion): " + ISODateTimeFormat.date().withZone( DateTimeZone.UTC ).print( dateTime ) );
System.out.println("dateTimePlus1: " + dateTimePlus1 );
System.out.println("dateTimePlus2: " + dateTimePlus2 );
System.out.println("dateTimePlus3: " + dateTimePlus3 );
When run…
dateTime: 2008-03-08T00:00:00.000Z
dateTime (date portion): 2008-03-08
dateTimePlus1: 2008-03-09T00:00:00.000Z
dateTimePlus2: 2008-03-10T00:00:00.000Z
dateTimePlus3: 2008-03-11T00:00:00.000Z

Related

How do I get the String type or timestamp type by giving a year

there is a requirement to get the startTime and endTime around the whole year by giving a int year, for example, given a variable int year = 2017, I want to get the starttime String "2017-01-01 00:00:00" and endtime String "2017-12-31 23:59:59", or get the starttime timestamp 1483200000 and endtime timestamp 1514735999. 2 results are ok to us, How should I do by java8 or below? I have known:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
String datetime = sdf.format(new Date(*timestamp*))
but I have no idea how I can get the timestamp by the given year, please help to check
int year = 2017;
// Using LocalDateTime (Java 8+ or Java 6+ with ThreeTen backport)
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
String start1 = LocalDateTime.of(year, Month.JANUARY, 1, 0, 0).format(dtf);
String stop1 = LocalDateTime.of(year, Month.DECEMBER, 31, 23, 59, 59).format(dtf);
System.out.println(start1 + " - " + stop1);
// Using Calendar (antiquated)
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Calendar cal = Calendar.getInstance();
cal.clear();
cal.set(year, Calendar.JANUARY, 1);
String start2 = sdf.format(cal.getTime());
cal.set(year, Calendar.DECEMBER, 31, 23, 59, 59);
String stop2 = sdf.format(cal.getTime());
System.out.println(start2 + " - " + stop2);
Output
2017-01-01 00:00:00 - 2017-12-31 23:59:59
2017-01-01 00:00:00 - 2017-12-31 23:59:59
Use a half-open interval
As Basil Bourque said in a comment: use a half-open interval. That is, define year 2017 as the time from the first moment of 2017 inclusive to the first moment of 2018 exclusive. So any moment that is on or after the start time and strictly before the end time belongs to the year.
Philosophical argument: It saves us from deciding whether to run up to the last second, the last millisecond or the last nanosecond of the year. An even if we rook the last nano, we would still have excluded a full nano from the year, which is incorrect. Yes, I know, your application only needs a granularity of seconds, so “it doesn’t matter”. But what if the next version does require a finer granularity? And even if it won’t, you should not want to fill errors or inaccuracies into your program, not even when the user doesn’t see any symptom of them.
Practical argument: A half-open interval simplifies some things, both when calculating the timestamps and when applying them.
ZoneId zone = ZoneId.of("Asia/Singapore");
Year year = Year.of(2017);
long startTime = year.atDay(1).atStartOfDay(zone).toEpochSecond();
System.out.println(startTime);
long endTime = year.plusYears(1).atDay(1).atStartOfDay(zone).toEpochSecond();
System.out.println(endTime);
Output from this snippet is:
1483200000
1514736000
If you absolutely insist, you may of course subtract 1 from the latter number.
Notice that using atStartOfDay() also saves us from assuming that the day begins at 00:00:00 and ends a second after 23:59:59. Funny time anomalies may cause this not to be the case. Such anomalies are in the time zone database and Java takes them into account when we just query the start of day in a time zone.
You can do like this using java.sql.Timestamp
import java.util.Date;
import java.sql.Timestamp;
public class Main
{
public static void main( String[] args )
{
Date date= new Date();
long time = date.getTime();
System.out.println("Time (Milliseconds): " + time);
Timestamp ts = new Timestamp(time);
System.out.println("Current Time Stamp: " + ts);
}
}
Using Java 8 only:
int year = 2017;
// using one of the predefined format from enum java.time.format.FormatStyle
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG);
LocalDateTime beginDate = LocalDateTime.of(year, Month.JANUARY, 1, 0, 0, 0);
LocalDateTime endDate = LocalDateTime.of(year, Month.DECEMBER, 31, 23, 59, 59);
String beginDateFormatted = beginDate.format(formatter);
String endDateFormatted = endDate.format(formatter);
long beginTimestamp = this.beginDate.toInstant(ZoneOffset.UTC).toEpochMilli();
long endTimestamp = this.endDate.toInstant(ZoneOffset.UTC).toEpochMilli();
Check working example here.

How do I convert date/time from one timezone to another? [duplicate]

i have written this code to convert the current system date and time to some other timezone. I am not getting any error but i am not getting my output as expected. Like if i execute my program at a particular time.. My output is ::
The current time in India is :: Fri Feb 24 16:09:23 IST 2012
The date and time in :: Central Standard Time is :: Sat Feb 25 03:39:23 IST 2012
And the actual Time according to CST time zone is ::
Friday, 24 February 4:39:16 a.m(GMT - 6:00)
So there's some time gap. and i don't know why this is happening. Any help will be appreciated.. The code is ::
package MyPackage;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class Temp2 {
public static void main(String[] args) {
try {
Calendar currentdate = Calendar.getInstance();
String strdate = null;
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
strdate = formatter.format(currentdate.getTime());
TimeZone obj = TimeZone.getTimeZone("CST");
formatter.setTimeZone(obj);
//System.out.println(strdate);
//System.out.println(formatter.parse(strdate));
Date theResult = formatter.parse(strdate);
System.out.println("The current time in India is :: " +currentdate.getTime());
System.out.println("The date and time in :: "+ obj.getDisplayName() + "is ::" + theResult);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
It's over the web. Could have googled. Anyways, here is a version for you (shamelessly picked and modified from here):
Calendar calendar = Calendar.getInstance();
TimeZone fromTimeZone = calendar.getTimeZone();
TimeZone toTimeZone = TimeZone.getTimeZone("CST");
calendar.setTimeZone(fromTimeZone);
calendar.add(Calendar.MILLISECOND, fromTimeZone.getRawOffset() * -1);
if (fromTimeZone.inDaylightTime(calendar.getTime())) {
calendar.add(Calendar.MILLISECOND, calendar.getTimeZone().getDSTSavings() * -1);
}
calendar.add(Calendar.MILLISECOND, toTimeZone.getRawOffset());
if (toTimeZone.inDaylightTime(calendar.getTime())) {
calendar.add(Calendar.MILLISECOND, toTimeZone.getDSTSavings());
}
System.out.println(calendar.getTime());
Your mistake is to call parse instead of format.
You call parse to parse a Date from a String, but in your case you've got a Date and need to format it using the correct Timezone.
Replace your code with
Calendar currentdate = Calendar.getInstance();
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
TimeZone obj = TimeZone.getTimeZone("CST");
formatter.setTimeZone(obj);
System.out.println("Local:: " +currentdate.getTime());
System.out.println("CST:: "+ formatter.format(currentdate.getTime()));
and I hope you'll get the output you are expecting.
SimpleDateFormat#setTimezone() is the answer. One formatter with ETC timezone you use for parsing, another with UTC for producing output string:
DateFormat dfNy = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ROOT);
dfNy.setTimeZone(TimeZone.getTimeZone("EST"));
DateFormat dfUtc = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ROOT);
dfUtc.setTimeZone(TimeZone.getTimeZone("UTC"));
try {
return dfUtc.format(dfNy.parse(input));
} catch (ParseException e) {
return null; // invalid input
}
Handling dates in Java in my daily work is a non-trivial task. I suggest you to use Joda-Time that simplify our coding days and you don't have to "re-invent the wheel".
You can use two SimpleDateFormat, one for parse the date string with EST timezone, one for print the date with UTC timezone
String format = "yyyy-MM-dd HH:mm:ss";
SimpleDateFormat estFormatter = new SimpleDateFormat(format);
estFormatter.setTimeZone(TimeZone.getTimeZone("EST"));
Date date = estFormatter.parse("2015-11-01 01:00:00");
SimpleDateFormat utcFormatter = new SimpleDateFormat(format);
utcFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(utcFormatter.format(date));
You can just use "CST6CDT"
because in some countries they follow CDT in summer and CST in winter
public static String getDateInCST() {
Calendar calendar = Calendar.getInstance();
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
formatter.setTimeZone(TimeZone.getTimeZone( "CST6CDT"));
String strdate = formatter.format(calendar.getTime());
TimeZone.getAvailableIDs();
return strdate;
}
Problem is when you print date obj it call toString method and it will print in your machines default time zone. Try this code and see difference.
Calendar currentdate = Calendar.getInstance();
String strdate = null;
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ssz");
strdate = formatter.format(currentdate.getTime());
System.out.println("strdate=>" + strdate);
TimeZone obj = TimeZone.getTimeZone("CST");
formatter.setTimeZone(obj);
strdate = formatter.format(currentdate.getTime());
Date theResult = formatter.parse(strdate);
System.out.println("The current time in India is :: " +currentdate.getTime());
System.out.println("The date and time in :: " + obj.getDisplayName() + "is ::" + theResult);
System.out.println("The date and time in :: " + obj.getDisplayName() + "is ::" + strdate);
First message, don’t handle your date and time as strings in your code. Just as you don’t handle numbers and Boolean values as strings (I hope). Use proper date-time objects.
java.time
Sometimes we get date and time as string input. It may be from a text file, from the user or from data exchange with another system, for example. In those cases parse into a proper date-time object first thing. Second message, use java.time, the modern Java date and time API, for your date and time work.
DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
String input = "2015-11-01 01:00:00";
ZonedDateTime nyTime = LocalDateTime.parse(input, formatter)
.atZone(ZoneId.of("America/New_York"));
System.out.println("Time in New York: " + nyTime);
Output from this snippet is:
Time in New York: 2015-11-01T01:00-04:00[America/New_York]
To convert to GMT:
OffsetDateTime gmtTime = nyTime.toOffsetDateTime()
.withOffsetSameInstant(ZoneOffset.UTC);
System.out.println("GMT Time: " + gmtTime);
GMT Time: 2015-11-01T05:00Z
If you need to give string output, format using a date-time formatter. Here’s an example of formatting for an American audience:
DateTimeFormatter userFormatter
= DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
.withLocale(Locale.US);
String formattedDateTime = gmtTime.format(userFormatter);
System.out.println("GMT Time formatted for user: " + formattedDateTime);
GMT Time formatted for user: Nov 1, 2015, 5:00:00 AM
You additionally asked:
Between the two results below, which one should you take?
I understand that you ask because both are valid answers. On November 1, 2015 summer time (DST) ended at 2 AM. That is, after 01:59:59 came 01:00:00 a second time. So when we have got 2015-11-01 01:00:00 as input, it is ambiguous. It could be in Eastern Daylight Time, equal to 05:00 GMT, or it could be in Eastern Standard Time, one hour later, hence equal to 06:00 GMT. There is no way that I can tell you which of them is correct in your case. You may control which result you get using withEarlierOffsetAtOverlap() or withLaterOffsetAtOverlap(). Above we got the DST interpretation. So to get the standard time interpretation:
nyTime = nyTime.withLaterOffsetAtOverlap();
System.out.println("Alternate time in New York: " + nyTime);
Alternate time in New York: 2015-11-01T01:00-05:00[America/New_York]
We notice that the hour of day is still 01:00, but the offset is now -05:00 instead of -04:00. This also gives us a different GMT time:
GMT Time: 2015-11-01T06:00Z
GMT Time formatted for user: Nov 1, 2015, 6:00:00 AM
Avoid SimpleDateFormat and friends
While the other answers are generally correct, the classes DateFormat, SimpleDateFormat, Date and Calendar used there are poorly designed and long outdated. The first two are particularly troublesome. I recommend you avoid all of them. I frankly find the modern API so much nicer to work with.
Link
Oracle tutorial: Date Time explaining how to use java.time.
Please refer to below mentioned code.
DateFormat utcConverter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
utcConverter.setTimeZone(TimeZone.getTimeZone("GMT"));
String sampleDateTime = "2015-11-01 01:00:00";
DateFormat nyConverter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
nyConverter.setTimeZone(TimeZone.getTimeZone("EST"));
Calendar nyCal = Calendar.getInstance();
nyCal.setTime(nyConverter.parse(sampleDateTime));
System.out.println("NY TIME :" +nyConverter.format(nyCal.getTime()));
System.out.println("GMT TIME :" +utcConverter.format(nyCal.getTime()));
2020 Answer Here
If you want the new java.time.* feature but still want to mess with java.util.Date:
public static Date convertBetweenTwoTimeZone(Date date, String fromTimeZone, String toTimeZone) {
ZoneId fromTimeZoneId = ZoneId.of(fromTimeZone);
ZoneId toTimeZoneId = ZoneId.of(toTimeZone);
ZonedDateTime fromZonedDateTime =
ZonedDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()).withZoneSameLocal(fromTimeZoneId);
ZonedDateTime toZonedDateTime = fromZonedDateTime
.withZoneSameInstant(toTimeZoneId)
.withZoneSameLocal(ZoneId.systemDefault())
;
return Date.from(toZonedDateTime.toInstant());
}
for java.sql.Timestamp
public static Timestamp convertBetweenTwoTimeZone(Timestamp timestamp, String fromTimeZone, String toTimeZone) {
ZoneId fromTimeZoneId = ZoneId.of(fromTimeZone);
ZoneId toTimeZoneId = ZoneId.of(toTimeZone);
LocalDateTime localDateTimeBeforeDST = timestamp.toLocalDateTime();
ZonedDateTime fromZonedDateTime = ZonedDateTime.of(localDateTimeBeforeDST, fromTimeZoneId);
ZonedDateTime toZonedDateTime = fromZonedDateTime.withZoneSameInstant(toTimeZoneId);
return Timestamp.valueOf(toZonedDateTime.toLocalDateTime());
}
For google calendar API
private String getFormatedDate(Date date)
{
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss+05:30");
df.setTimeZone(TimeZone.getTimeZone("GMT+05:30"));
return df.format(date);
}

Calendar timezone , how does it work?

When I execute the below snippet
public static void main(String[] args) {
TimeZone timeZoneInd = TimeZone.getTimeZone("Asia/Calcutta");
TimeZone timeZoneAus = TimeZone.getTimeZone("Australia/Adelaide");
Calendar calendarInd = Calendar.getInstance(timeZoneInd);
Calendar calendarAus = Calendar.getInstance(timeZoneAus);
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy-HH:mm:ss SSSS");
System.out.println("Australian time now :" + sdf.format(calendarAus.getTime()));
System.out.println("Indian time now :" + sdf.format(calendarInd.getTime()));
}
Why is it that both values are same ? Should'nt each print time corresponding to its timezone ?
That is because the time in each Calendar object is the same. If you want to format dates for different time zones, you will need to set the time zone in the format object, like this:
TimeZone timeZoneInd = TimeZone.getTimeZone("Asia/Calcutta");
TimeZone timeZoneAus = TimeZone.getTimeZone("Australia/Adelaide");
SimpleDateFormat formatInd = new SimpleDateFormat("dd/MM/yyyy-HH:mm:ss SSSS");
formatInd.setTimeZone(timeZoneInd);
SimpleDateFormat formatAus = new SimpleDateFormat("dd/MM/yyyy-HH:mm:ss SSSS");
formatAus.setTimeZone(timeZoneAus);
Calendar calendarInd = Calendar.getInstance(timeZoneInd);
Calendar calendarAus = Calendar.getInstance(timeZoneAus);
System.out.println("Australian time now :" + formatAus.format(new Date()));
System.out.println("Indian time now :" + formatInd.format(new Date()));
calendarAus.set(Calendar.HOUR_OF_DAY, 12);
calendarInd.set(Calendar.HOUR_OF_DAY, 12);
System.out.println("Australian time at noon :" + formatAus.format(calendarAus.getTime()));
System.out.println("Indian time at noon :" + formatInd.format(calendarInd.getTime()));
This for me gives the following output:
Australian time now :20/02/2015-23:00:51 0081
Indian time now :20/02/2015-18:00:51 0082
Australian time at noon :20/02/2015-12:00:51 0081
Indian time at noon :20/02/2015-12:00:51 0081
You should use the SimpleDateFormat for formatting your dates, the Calendar object should be used for manipulating dates.

Format a Date object with DateFormat in Java

I'm trying to learn about Date objects and the DateFormat class and I keep getting an error in the examples I'm trying to do. The goal is to get a due date by adding 30 days to a pretend invoice date, and then to format that due date. The dueDate method, I believe, is correct, but I'm having trouble formatting it properly.
Here is the first thing I have that takes the invoice date and adds 30 days to it.
public Date getDueDate()
{
Calendar cal = new GregorianCalendar();
cal.setTime(getInvoiceDate());
cal.add(Calendar.DATE, 30);
Date dueDate = cal.getTime();
return dueDate;
}
The next part is where I'm having the trouble, as it keeps telling me it expects a Date object but is receiving a String and I'm not sure why, as I'm supplying a Date object.
public Date getFormattedDueDate()
{
Date dueDate = getDueDate();
DateFormat shortDate = DateFormat.getDateInstance(DateFormat.SHORT);
return shortDate.format(dueDate);
}
Can anyone help me figure out why it's telling me that my supplied variable (dueDate) is a String when it's coded as a Date object?
format(Date date) Formats a Date into a date/time String.
Shamse is right
shortDate.format(dueDate);
returns a String, you can easly fix this changing your return type
public String getFormattedDueDate()
{
Date dueDate = getDueDate();
DateFormat shortDate = DateFormat.getDateInstance(DateFormat.SHORT);
return shortDate.format(dueDate);
}
The answer by Shamse is correct.
For the heck of it, here's the same kind of code but:
Written using the third-party library, Joda-Time 2.3
Care taken with time zones. Depending on default time zones is risky.
// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
java.util.Date date = new Date(); // = getInvoiceDate();
org.joda.time.DateTime invoiceStoredDateTime = new org.joda.time.DateTime( date );
// Set to desired time zone. Ideally that invoice date was stored in UTC.
// Time Zone list: http://joda-time.sourceforge.net/timezones.html
org.joda.time.DateTimeZone denverTimeZone = org.joda.time.DateTimeZone.forID( "America/Denver" );
org.joda.time.DateTime invoiceZonedDateTime = invoiceStoredDateTime.toDateTime( denverTimeZone );
// Call method .withTimeAtStartOfDay() to set the time component to first moment of the day.
org.joda.time.DateTime dueDateInThirtyDays = invoiceZonedDateTime.plusDays( 30 ).withTimeAtStartOfDay();
org.joda.time.DateTime dueDateInOneMonth = invoiceZonedDateTime.plusMonths( 1 ).withTimeAtStartOfDay(); // Smart month calculation, aiming at same day number of month.
// Style – Specify a character of 'S' for short style, 'M' for medium, 'L' for long, and 'F' for full. First for date, second for time.
// A date or time may be omitted by specifying a style character '-'.
String dueDateAsString = org.joda.time.format.DateTimeFormat.forStyle("S-").withLocale( Locale.US ).print( dueDateInThirtyDays );
org.joda.time.DateTime dueDateInUtcForStorage = dueDateInThirtyDays.toDateTime( org.joda.time.DateTimeZone.UTC );
Show values on the console:
System.out.println( "date: " + date );
System.out.println( "invoiceZonedDateTime: " + invoiceZonedDateTime );
System.out.println( "dueDateInThirtyDays: " + dueDateInThirtyDays );
System.out.println( "dueDateInOneMonth: " + dueDateInOneMonth );
System.out.println( "dueDateAsString: " + dueDateAsString );
System.out.println( "dueDateInUtcForStorage: " + dueDateInUtcForStorage );
When run…
date: Thu Nov 28 13:39:05 PST 2013
invoiceZonedDateTime: 2013-11-28T14:39:05.125-07:00
dueDateInThirtyDays: 2013-12-28T00:00:00.000-07:00
dueDateInOneMonth: 2013-12-28T00:00:00.000-07:00
dueDateAsString: 12/28/13
dueDateInUtcForStorage: 2013-12-28T07:00:00.000Z

Date and time conversion to some other Timezone in java

i have written this code to convert the current system date and time to some other timezone. I am not getting any error but i am not getting my output as expected. Like if i execute my program at a particular time.. My output is ::
The current time in India is :: Fri Feb 24 16:09:23 IST 2012
The date and time in :: Central Standard Time is :: Sat Feb 25 03:39:23 IST 2012
And the actual Time according to CST time zone is ::
Friday, 24 February 4:39:16 a.m(GMT - 6:00)
So there's some time gap. and i don't know why this is happening. Any help will be appreciated.. The code is ::
package MyPackage;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class Temp2 {
public static void main(String[] args) {
try {
Calendar currentdate = Calendar.getInstance();
String strdate = null;
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
strdate = formatter.format(currentdate.getTime());
TimeZone obj = TimeZone.getTimeZone("CST");
formatter.setTimeZone(obj);
//System.out.println(strdate);
//System.out.println(formatter.parse(strdate));
Date theResult = formatter.parse(strdate);
System.out.println("The current time in India is :: " +currentdate.getTime());
System.out.println("The date and time in :: "+ obj.getDisplayName() + "is ::" + theResult);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
It's over the web. Could have googled. Anyways, here is a version for you (shamelessly picked and modified from here):
Calendar calendar = Calendar.getInstance();
TimeZone fromTimeZone = calendar.getTimeZone();
TimeZone toTimeZone = TimeZone.getTimeZone("CST");
calendar.setTimeZone(fromTimeZone);
calendar.add(Calendar.MILLISECOND, fromTimeZone.getRawOffset() * -1);
if (fromTimeZone.inDaylightTime(calendar.getTime())) {
calendar.add(Calendar.MILLISECOND, calendar.getTimeZone().getDSTSavings() * -1);
}
calendar.add(Calendar.MILLISECOND, toTimeZone.getRawOffset());
if (toTimeZone.inDaylightTime(calendar.getTime())) {
calendar.add(Calendar.MILLISECOND, toTimeZone.getDSTSavings());
}
System.out.println(calendar.getTime());
Your mistake is to call parse instead of format.
You call parse to parse a Date from a String, but in your case you've got a Date and need to format it using the correct Timezone.
Replace your code with
Calendar currentdate = Calendar.getInstance();
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
TimeZone obj = TimeZone.getTimeZone("CST");
formatter.setTimeZone(obj);
System.out.println("Local:: " +currentdate.getTime());
System.out.println("CST:: "+ formatter.format(currentdate.getTime()));
and I hope you'll get the output you are expecting.
SimpleDateFormat#setTimezone() is the answer. One formatter with ETC timezone you use for parsing, another with UTC for producing output string:
DateFormat dfNy = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ROOT);
dfNy.setTimeZone(TimeZone.getTimeZone("EST"));
DateFormat dfUtc = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ROOT);
dfUtc.setTimeZone(TimeZone.getTimeZone("UTC"));
try {
return dfUtc.format(dfNy.parse(input));
} catch (ParseException e) {
return null; // invalid input
}
Handling dates in Java in my daily work is a non-trivial task. I suggest you to use Joda-Time that simplify our coding days and you don't have to "re-invent the wheel".
You can use two SimpleDateFormat, one for parse the date string with EST timezone, one for print the date with UTC timezone
String format = "yyyy-MM-dd HH:mm:ss";
SimpleDateFormat estFormatter = new SimpleDateFormat(format);
estFormatter.setTimeZone(TimeZone.getTimeZone("EST"));
Date date = estFormatter.parse("2015-11-01 01:00:00");
SimpleDateFormat utcFormatter = new SimpleDateFormat(format);
utcFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(utcFormatter.format(date));
You can just use "CST6CDT"
because in some countries they follow CDT in summer and CST in winter
public static String getDateInCST() {
Calendar calendar = Calendar.getInstance();
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
formatter.setTimeZone(TimeZone.getTimeZone( "CST6CDT"));
String strdate = formatter.format(calendar.getTime());
TimeZone.getAvailableIDs();
return strdate;
}
Problem is when you print date obj it call toString method and it will print in your machines default time zone. Try this code and see difference.
Calendar currentdate = Calendar.getInstance();
String strdate = null;
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ssz");
strdate = formatter.format(currentdate.getTime());
System.out.println("strdate=>" + strdate);
TimeZone obj = TimeZone.getTimeZone("CST");
formatter.setTimeZone(obj);
strdate = formatter.format(currentdate.getTime());
Date theResult = formatter.parse(strdate);
System.out.println("The current time in India is :: " +currentdate.getTime());
System.out.println("The date and time in :: " + obj.getDisplayName() + "is ::" + theResult);
System.out.println("The date and time in :: " + obj.getDisplayName() + "is ::" + strdate);
First message, don’t handle your date and time as strings in your code. Just as you don’t handle numbers and Boolean values as strings (I hope). Use proper date-time objects.
java.time
Sometimes we get date and time as string input. It may be from a text file, from the user or from data exchange with another system, for example. In those cases parse into a proper date-time object first thing. Second message, use java.time, the modern Java date and time API, for your date and time work.
DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
String input = "2015-11-01 01:00:00";
ZonedDateTime nyTime = LocalDateTime.parse(input, formatter)
.atZone(ZoneId.of("America/New_York"));
System.out.println("Time in New York: " + nyTime);
Output from this snippet is:
Time in New York: 2015-11-01T01:00-04:00[America/New_York]
To convert to GMT:
OffsetDateTime gmtTime = nyTime.toOffsetDateTime()
.withOffsetSameInstant(ZoneOffset.UTC);
System.out.println("GMT Time: " + gmtTime);
GMT Time: 2015-11-01T05:00Z
If you need to give string output, format using a date-time formatter. Here’s an example of formatting for an American audience:
DateTimeFormatter userFormatter
= DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
.withLocale(Locale.US);
String formattedDateTime = gmtTime.format(userFormatter);
System.out.println("GMT Time formatted for user: " + formattedDateTime);
GMT Time formatted for user: Nov 1, 2015, 5:00:00 AM
You additionally asked:
Between the two results below, which one should you take?
I understand that you ask because both are valid answers. On November 1, 2015 summer time (DST) ended at 2 AM. That is, after 01:59:59 came 01:00:00 a second time. So when we have got 2015-11-01 01:00:00 as input, it is ambiguous. It could be in Eastern Daylight Time, equal to 05:00 GMT, or it could be in Eastern Standard Time, one hour later, hence equal to 06:00 GMT. There is no way that I can tell you which of them is correct in your case. You may control which result you get using withEarlierOffsetAtOverlap() or withLaterOffsetAtOverlap(). Above we got the DST interpretation. So to get the standard time interpretation:
nyTime = nyTime.withLaterOffsetAtOverlap();
System.out.println("Alternate time in New York: " + nyTime);
Alternate time in New York: 2015-11-01T01:00-05:00[America/New_York]
We notice that the hour of day is still 01:00, but the offset is now -05:00 instead of -04:00. This also gives us a different GMT time:
GMT Time: 2015-11-01T06:00Z
GMT Time formatted for user: Nov 1, 2015, 6:00:00 AM
Avoid SimpleDateFormat and friends
While the other answers are generally correct, the classes DateFormat, SimpleDateFormat, Date and Calendar used there are poorly designed and long outdated. The first two are particularly troublesome. I recommend you avoid all of them. I frankly find the modern API so much nicer to work with.
Link
Oracle tutorial: Date Time explaining how to use java.time.
Please refer to below mentioned code.
DateFormat utcConverter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
utcConverter.setTimeZone(TimeZone.getTimeZone("GMT"));
String sampleDateTime = "2015-11-01 01:00:00";
DateFormat nyConverter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
nyConverter.setTimeZone(TimeZone.getTimeZone("EST"));
Calendar nyCal = Calendar.getInstance();
nyCal.setTime(nyConverter.parse(sampleDateTime));
System.out.println("NY TIME :" +nyConverter.format(nyCal.getTime()));
System.out.println("GMT TIME :" +utcConverter.format(nyCal.getTime()));
2020 Answer Here
If you want the new java.time.* feature but still want to mess with java.util.Date:
public static Date convertBetweenTwoTimeZone(Date date, String fromTimeZone, String toTimeZone) {
ZoneId fromTimeZoneId = ZoneId.of(fromTimeZone);
ZoneId toTimeZoneId = ZoneId.of(toTimeZone);
ZonedDateTime fromZonedDateTime =
ZonedDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()).withZoneSameLocal(fromTimeZoneId);
ZonedDateTime toZonedDateTime = fromZonedDateTime
.withZoneSameInstant(toTimeZoneId)
.withZoneSameLocal(ZoneId.systemDefault())
;
return Date.from(toZonedDateTime.toInstant());
}
for java.sql.Timestamp
public static Timestamp convertBetweenTwoTimeZone(Timestamp timestamp, String fromTimeZone, String toTimeZone) {
ZoneId fromTimeZoneId = ZoneId.of(fromTimeZone);
ZoneId toTimeZoneId = ZoneId.of(toTimeZone);
LocalDateTime localDateTimeBeforeDST = timestamp.toLocalDateTime();
ZonedDateTime fromZonedDateTime = ZonedDateTime.of(localDateTimeBeforeDST, fromTimeZoneId);
ZonedDateTime toZonedDateTime = fromZonedDateTime.withZoneSameInstant(toTimeZoneId);
return Timestamp.valueOf(toZonedDateTime.toLocalDateTime());
}
For google calendar API
private String getFormatedDate(Date date)
{
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss+05:30");
df.setTimeZone(TimeZone.getTimeZone("GMT+05:30"));
return df.format(date);
}

Categories