When I run the following code snippet:
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Date;
public class TimestampTest {
public static void main(String... args) throws Exception {
Date aDate1880 = new Date(-20, 0, 1);
Timestamp timestamp = new Timestamp(aDate1880.getTime());
DateTime dateTime = new DateTime(timestamp).withZoneRetainFields(DateTimeZone.getDefault());
System.out.println(dateTime.year().get());
Calendar calendar = Calendar.getInstance();
calendar.setTime(timestamp);
System.out.println(calendar.get(Calendar.YEAR));
}
}
I get the following output:
1879
1880
As aDate1880 does actually represents year 1880 I don't know why Joda DateTime gives year as 1879. Any help would be appreciated.
This code:
Date aDate1880 = new Date(-20, 0, 1);
Creates a Date equivalent to January 1st 1880. As the time fields were not provided, they are set to midnight at the JVM default timezone. In my case, it's "America/Sao_Paulo", so the results below might be different in your case - but it'd explain what's happening anyway. In my case, the date created is:
Thu Jan 01 00:00:00 BRT 1880
(January 1st 1880 at midnight in America/Sao_Paulo timezone - BRT means "Brazilian Time")
Calling aDate1880.getTime() returns the value -2840130000000, which corresponds in UTC to 1880-01-01T03:00:00Z.
When converting to DateTime, it uses joda-time internal timezone data, an in my case the DateTime is:
1879-12-31T23:53:32.000-03:06:28
That's because before 1900, many countries didn't use current timezone rules, and most cities had their own local time. And most offsets were calculated based on the longitude, and that's why it has such strange results like "-03:06:28".
Probably your timezone has a similar issue.
Note: new DateTime(timestamp) already uses the default timezone, so the call to withZoneRetainFiels is redundant:
DateTime dateTime = new DateTime(timestamp);
// this prints "true"
System.out.println(dateTime.equals(dateTime.withZoneRetainFields(DateTimeZone.getDefault())));
To create the date you want, you can use only Joda-Time classes:
// January 1st 1880, at midnight in JVM default timezone
DateTime d = new LocalDate(1880, 1, 1).toDateTimeAtStartOfDay();
Related
This question already has answers here:
How to handle dates when the input dates are in the transition period from PDT to PST?
(2 answers)
Closed 3 years ago.
In short:
I have a time that is in epoch and I want to make it time since January 1, 1970, 00:00:00 GMT as java.util.Date would expect to be given.
This code helps demonstrate my issue:
import java.util.Date;
import java.util.Locale;
import org.junit.Test;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
public class TimeHelp {
private String format = "EEE MMM dd HH:mm:ss yyyy";
public SimpleDateFormat asSimpleDateFormat() {
return new SimpleDateFormat(format, Locale.ENGLISH);
}
public DateTimeFormatter asDateTimeFormatter() {
return DateTimeFormatter.ofPattern(format, Locale.ENGLISH);
}
#Test
public void test() throws Exception {
System.out.println(ZoneId.systemDefault());
String s = "Sun Apr 04 02:00:01 2010";
long t1 = asSimpleDateFormat().parse(s).getTime();
ZonedDateTime zoned = LocalDateTime.parse(s, asDateTimeFormatter())
.atZone(ZoneId.systemDefault());
long t2 = zoned.toEpochSecond() * 1000;
long t3 = Date.from(zoned.toInstant()).getTime();
long t4 = zoned.toInstant().toEpochMilli();
System.out.println("t1 " + t1);
System.out.println("t2 " + t2);
System.out.println("t3 " + t3);
System.out.println("t4 " + t4);
System.out.println("Difference in minutes " + Math.abs(t1 - t2)/1000/60);
}
}
And that outputs:
Australia/Sydney
t1 1270310401000
t2 1270306801000
t3 1270306801000
t4 1270306801000
Difference in minutes 60
Note that t1 is different from all the others, I think because t1 is GMT while the others are all UTC.
If I use the SimpleDateFormat the value of the long is different to if I use the DateTimeFormatter to get a ZonedDateTime after which I call toEpochSecond().
For reasons I would like to be given a ZonedDateTime and I want to convert that to a Date but it looks like such a thing wont work because the Date works in GMT not UTC.
Quoting timeanddate.com:
When local daylight time was about to reach Sunday, April 4, 2010, 3:00:00 am clocks were turned backward 1 hour to Sunday, April 4, 2010, 2:00:00 am local standard time instead.
Which means that Sun Apr 04 02:00:01 2010 happened twice that day. So which of those 2 do you get?
With SimpleDateFormat you get the later one, although that is undocumented.
With ZonedDateTime you get the earlier one:
For Overlaps, the general strategy is that if the local date-time falls in the middle of an Overlap, then the previous offset will be retained. If there is no previous offset, or the previous offset is invalid, then the earlier offset is used, typically "summer" time.. Two additional methods, withEarlierOffsetAtOverlap() and withLaterOffsetAtOverlap(), help manage the case of an overlap.
GregorianCalendar test= new GregorianCalendar();
BigDecimal coef=new BigDecimal(-2113480800);
test.setGregorianChange(new Date(Long.MIN_VALUE));
test.set(Calendar.DAY_OF_MONTH, 31);
test.set(Calendar.MONTH, 11);
test.set(Calendar.YEAR, 1600);
test.add(Calendar.DAY_OF_MONTH,-583657);
System.out.println((test.getTime()));
// I should get Jan 1 0003 but i get 03 jan 0003 OFFSET of 2
The calendar you're using is fine - you just need to remember that a Date only stores an instant in time. It doesn't remember a calendar, time zone or text format.
The Date value you've got is correct - it has an epoch millis of -62072462953058, which corresponds to 0003-01-01T17:10:46Z (at least for me - depends on time at which you run the code) in a system which doesn't use the Gregorian change.
However, Date.toString() formats that instant as if there was a Gregorian change, leading to the two day offset.
You can see this by using Java 8's Instant instead:
import java.time.*;
import java.util.*;
public class Test {
public static void main (String args[]) {
GregorianCalendar test = new GregorianCalendar();
test.setGregorianChange(new Date(Long.MIN_VALUE));
test.set(Calendar.DAY_OF_MONTH, 31);
test.set(Calendar.MONTH, 11);
test.set(Calendar.YEAR, 1600);
test.add(Calendar.DAY_OF_MONTH,-583657);
Date date = test.getTime();
Instant instant = Instant.ofEpochMilli(date.getTime());
System.out.println(date);
System.out.println(instant);
}
}
Output (at the moment, in London):
Wed Jan 03 17:15:26 GMT 3
0003-01-01T17:15:26.913Z
The two values represent the same point in time, but the Instant conversion to string doesn't perform a Julian/Gregorian cutover, whereas Date does.
I have a scenario where I need to convert a date time string from Timezone A(UTC) to Timezone B(EST).
Catch here is the JVM where this transformation is happening is Timezone C(HKT) Date Object.
So the code block is as follows:
String dateString="20141114213000";
dateString += " UTC";
String formatString ="yyyyMMddHHmmss";
SimpleDateFormat sdf = new SimpleDateFormat(formatString + " z");
Date localDate = sdf.parse(dateString);
System.out.println("Local Date::"+localDate); // Local Date::Sat Nov 15 05:30:00 HKT 2014
Calendar localCal = Calendar.getInstance();
localCal.setTime(localDate);
TimeZone estTimeZone = TimeZone.getTimeZone("America/New_York");
localCal.setTimeZone(estTimeZone);
sdf.setTimeZone(estTimeZone);
System.out.println(sdf.format(localCal.getTime()));//20141114163000 EST
System.out.println(localCal.getTime());//Sat Nov 15 05:30:00 HKT 2014
The output I am expecting is to be "Fri Nov 14 16:30:00 EST 2014" from the last statement, i.e., the final date object available should be in EST.
Please let know if anyone has info on this.
Update:
Just to make my request clear, output should be in Date object only.
The sample code and the output I printed is only for clearer explanation.
So basically String "20141114213000" which is a UTC Date String needs to be converted to EST Date Object and JVM where this transformation is happening is in HKT.
There seems to be notable issues with Java's Date and Time classes.
Lets use the popular Joda-Time - Java date and time API.
Simply download the newest stable release and add the jar files to your project's build path.
On a line-by-line basis, I have commented out your code and rewritten the Joda Time alternative. This way you can understand how I transitioned your existing code to the Joda Time API.
import java.text.ParseException;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
public class JodaTimeTransition {
public static void main(String[] args) throws ParseException {
String dateString="20141114213000";
dateString += " UTC";
/*new*/
String formatString = "yyyyMMddHHmmss z";
// String formatString ="yyyyMMddHHmmss";
/*new*/
DateTimeFormatter dtf = DateTimeFormat.forPattern(formatString);
// SimpleDateFormat sdf = new SimpleDateFormat(formatString + " z");
/* new - Create localDate using JodaTime DateTime class */
DateTime localDate = DateTime.parse(dateString, dtf);
// Date localDate = sdf.parse(dateString);
/* new - convert time to MST, since it is currently UTC*/
localDate = localDate.toDateTime(DateTimeZone.forID("America/Denver"));
/* new - print out <local date> using specified format.*/
System.out.println("Local Date::" + localDate.toString("EEE MMM dd HH:mm:ss z yyyy"));
/* Where did you get the local date mentioned at comments of line below? */
// System.out.println("Local Date::"+localDate); // Local Date::Sat Nov 15 05:30:00 HKT 2014
/* new - Get reference to current date/time as <localCal>
* (This step can be omitted, and the previous localDate variable can be used)
*/
DateTime localCal = DateTime.now();
// Calendar localCal = Calendar.getInstance();
/* new - Set <localCal> to <localDate> */
localCal = localDate;
// localCal.setTime(localDate);
/* new - Create new EST time zone*/
DateTimeZone estTimeZone= DateTimeZone.forID("America/New_York");
// TimeZone estTimeZone = TimeZone.getTimeZone("America/New_York");
/* new - set <localCal> time zone from MST to EST */
localCal = localCal.toDateTime(estTimeZone);
// localCal.setTimeZone(estTimeZone);
// sdf.setTimeZone(estTimeZone);
/* new - print <localCal> as new EST time zone */
System.out.println(localCal.toString("yyyyMMddHHmmss z"));
// System.out.println(sdf.format(localCal.getTime()));//20141114163000 EST
/* new - print in desired format: Fri Nov 14 16:30:00 EST 2014 */
System.out.println(localCal.toString("EEE MMM dd HH:mm:ss z yyyy"));
// System.out.println(localCal.getTime());//Sat Nov 15 05:30:00 HKT 2014
}
}
This is actually very straightforward (no need for Joda time, not that it isn't a great library), you just need to set the TimeZone on the SimpleDateFormat. Use the source TimeZone when you parse, then the destination TimeZone when you format (and you don't need the intermediate Calendar).
UPDATE:
Date's don't have TimeZones. If you want something with a TimeZone (other than a String), then you will need a Calendar. Your current code is mostly correct except that you haven't set the source TimeZone on the SimpleDateFormat before parsing.
Update
After some discussion in the comments, it seems now clear that you should not rely on java.util.Date for time zones at all. The trick sketched below (my original answer) will probably work, but it is not the right thing to do. Switch to something which supports time zones (java.util.Calendar for instance), but better use JodaTime.
Warning: this is a trick which may (or may not) work for Sun's implementation of java.util.Date whose internal structures are initialized with a time zone.
Try setting the default time zone with TimeZone.setDefault(...) first.
Your last call:
System.out.println(localCal.getTime());
Is actually:
System.out.println(new Date(localCal.getTimeInMillis()).toString());
So setting any time zone info on the calendar is pointless.
Date.toString(), however first does an internal normalization on the date and uses the static TimeZone.getDefaultRef(). This should give you the default time zone - which you can (normally) set via TimeZone.setDefailt(...).
And by all means use JodaTime.
I have a date For Eg: 2014-04-22 08:22:41 and I have to get the representation of the date in seconds from GMT-5 timezone which is 12/31/1969 19:00:00.
I have the following code:
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class samp {
public static void main(String args[]) {
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT-5:00"));
long temp;
Date tempDate = null;
temp = 0L;
cal.clear();
try {
tempDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2014-04-22 08:22:41");
} catch (Exception e) {
}
cal.setTime(tempDate);
temp = cal.getTimeInMillis() / 1000L;
cal.clear();
System.out.println("Second representation is " + (int) temp);
}
}
The output is : Second representation is 1398135161
But when I get the same value from Sybase Database I get the value:
select DateDiff(ss,'12/31/1969 19:00:00','04/22/2014 08:22:41') = 1398172961
Why is there a difference between the java result and the database value.
Is there something wring in java code.
Please clarify.
They are using different timezones
your database is working off of your set timezone but in your calendar you are not using the same timezone when you get the millis.
1398135161 * 1000 can equal in millis
Date (America/New_York) Monday, April 21, 2014 10:52:41 PM EDT
Date (GMT) Tuesday, April 22, 2014 2:52:41 AM GMT
it is all relative to timezone.
There are websites like these that can help you out when in doubt
http://www.ruddwire.com/handy-code/date-to-millisecond-calculators/#.U1dtG-bqfCc
http://www.fileformat.info/tip/java/date2millis.htm
As you can find at the oracle documentation site:
http://docs.oracle.com/javase/6/docs/api/java/util/Calendar.html#getTimeInMillis()
getTimeInMillis returns the time in UTC
You can adjust that value to your timezone using:
cal.getTimeZone().getOffset(UTCmilliseconds)
Which (as it is described at http://docs.oracle.com/javase/6/docs/api/java/util/TimeZone.html#getOffset(long)) returns the amount of milliseconds you have to add to UTC time to get your localtime in milliseconds.
Being your zone-adjusted time given by:
cal.setTime(tempDate);
temp = cal.getTimeInMillis();
temp = (temp + (long)(cal.getTimeZone().getOffset(temp)))/ 1000L;
Adjust Date-Time, Not Epoch
You should be thinking about adjusting your date-time value not the epoch.
Use Time Zone, Not Offset
You should probably be using proper time zone names, not a specific offset number because of Daylight Saving Time and other anomalies. Unless you are absolutely certain your date-values were always adjusted by that specific offset.
Avoid j.u.Date
You should be using a decent library rather than the notoriously difficult java.util.Date and .Calendar classes. That means either Joda-Time or the new java.time package in Java 8.
Joda-Time
Here is example code in Joda-Time.
String inputRaw = "2014-01-02 12:34:56";
String input = inputRaw.replace( " ", "T" );
DateTimeZone timeZone = DateTimeZone.forID( "America/Detroit" );
DateTime dateTime = new DateTime( input, timeZone );
long millis = dateTime.getMillis();
Long seconds = ( millis / 1000L );
I have following method which convert my custom DMY (date,month,year) object to Date.
public static Date serverCreateDateFromDMY(DMY pDMY, TimeZone pTimeZone)
{
Calendar vCalendar = Calendar.getInstance(pTimeZone);
vCalendar.set(Calendar.YEAR, pDMY.getYear());
// Below line is because DMY month counts are 1-indexed
// and Date month counts are 0-indexed
vCalendar.set(Calendar.MONTH, pDMY.getMonthOfYear() - 1);
vCalendar.set(Calendar.DAY_OF_MONTH, pDMY.getDayOfMonth());
System.out.println(vCalendar.getTime());
TimeUtilsServer.zeroCalendarHoursAndBelow(vCalendar);
System.out.println(vCalendar.getTime());
return vCalendar.getTime();
}
public static void zeroCalendarHoursAndBelow(Calendar pToZero)
{
pToZero.set(Calendar.HOUR_OF_DAY, 0);
pToZero.set(Calendar.MINUTE, 0);
pToZero.set(Calendar.SECOND, 0);
pToZero.set(Calendar.MILLISECOND, 0);
}
to serverCreateDateFromDMY() method, I am passing these arguments : DMY=20120424, and TimeZone is : America/New_York. Application is running locally in my timezone which is IST.
based in above inputs, following output is printed.
Tue Apr 24 14:43:07 IST 2012
Tue Apr 24 09:30:00 IST 2012
so as you see that in last output time is not zeroed out. any suggestions please?
#Marko, yes I come to know about DateFormat and I tried following example. but still date is printed with time and not zeroing out.
TimeZone tz = TimeZone.getTimeZone("America/New_York");
Calendar vCalendar = Calendar.getInstance(tz);
vCalendar.set(Calendar.YEAR, 2012);
vCalendar.set(Calendar.MONTH, 4 - 1);
vCalendar.set(Calendar.DAY_OF_MONTH, 24);
DateFormat df = DateFormat.getDateTimeInstance();
df.setTimeZone(tz);
System.out.println(df.format(vCalendar.getTime()));
vCalendar.set(Calendar.HOUR_OF_DAY, vCalendar.getActualMinimum(Calendar.HOUR_OF_DAY));
vCalendar.set(Calendar.MINUTE, vCalendar.getActualMinimum(Calendar.MINUTE));
vCalendar.set(Calendar.SECOND, vCalendar.getActualMinimum(Calendar.SECOND));
vCalendar.set(Calendar.MILLISECOND, vCalendar.getActualMinimum(Calendar.MILLISECOND));
System.out.println(df.format(vCalendar.getTime()));
java Date / Time API have a bad design from the time of its creation. Maybe you should take a look at some library - for example this which hides JDK API deficiencies - http://joda-time.sourceforge.net/
Internally, Date and Calendar objects are stored in UTC. When you set the fields to 0, the Calendar is updated in UTC.
When you ask the Calendar for the time, it then converts the Date to your desired Timezone, hence the difference.
... and you are 9:30h ahead of NY time. You set the time to midnight NY time and read it out as time in your zone. Note that getTime returns a Date, which is not timezone-configurable. You'll need DateFormat if you want to specify the timezone for which you print the result.