I need to calculate period between two dates, one date is now. And I'm using SimpleDateFormat for formatting date.
public String getPeriod(Date endDate) {
String format;
Date now = new Date();
long period = endDate.getTime() - now.getTime();
if (now.after(endDate)) {
return "passed";
} else {
if (period < 1000 * 60 * 60)
format = "m'M' s'S'";
else if (period < 1000 * 60 * 60 * 24)
format = "k'H' m'M'";
else
format = "'Too much'";
SimpleDateFormat formatter = new SimpleDateFormat(format);
return formatter.format(new Date(period)) + " / for testing - " + period / 3600000 + " hours";
}
}
As a result I have following input for example if endDate equals Wed Nov 12 13:30:02 EET 2014 (EST):
1 H 36 M / for testing - 22 hours
As you can see my test calculation and format's method result do not match. What am i doing wrong?
The difference is due to the timezone. For example, in my case, given as the parameter the time that would be in an hour, I get 3H as output, because the date would be Thu Jan 01 03:00:00 EET 1970. Notice the EET (I'm from Eastern Europe).
Your code would work if you'd notify java to use GMT time, as it says in the new Date(long) description:
Allocates a Date object and initializes it to represent the specified
number of milliseconds since the standard base time known as "the
epoch", namely January 1, 1970, 00:00:00 GMT.
Also, keep in mind that Date does not give perfect results. Using programatically determined dates exactly 1h appart (no millies / minutes difference), date calculations give an offset of 59 minutes, 59 seconds and 999 milies. If you require more exact values, you should use nanoseconds.
However, the other commenters are right. You should not use Java Date / Calendar in such a way, as it is a bug factory (this is only one corner case). You should check out other libraries (such as yoda time), or if you only need simple calculations such as this, do it yourself.
Hope it helps.
Related
This question already has answers here:
How can I create a Java 8 LocalDate from a long Epoch time in Milliseconds?
(8 answers)
Calculate days between two Dates in Java 8
(14 answers)
Closed 4 years ago.
I want to calculate how many day difference between 2 timestamps, but i do not want to consider the time difference.
For example :
long time1 = 1546258765000 (Mon 31 December 2018 13:19:25)
long time2 = 1546005915367 (Fri 28 December 2018 15:05:15)
The result should be 3, 3 days left for expire...
Due to time I get 2 from this method:
TimeUnit.DAYS.convert(time1 - time2 , TimeUnit.MILLISECONDS))
I just need to set the time same for both time1 and time2, and then go back to timestamp and calculate like this... but I am not sure what is the best way to do it.
NOTE: As noted by Ole V.V: this only works for UTC. Since timestamps are always on UTC, if you are in another timezone it might return undesired results. Example:
In GMT + 1:
time1 = 1546216200000L (Mon 31 December 2018 01:30:00) (31/12 00:30 on UTC)
time2 = 1545953400000L (Fri 28 December 2018 00:30:00) (27/12 11:30 on UTC)
This will result in a 4 days difference, since that's the difference on UTC.
To compensate that, you should offset the difference so the timestamps show your current time, instead of UTC time. (If you are in GMT+1, for example, you will need to add 1 hour (3600000 ms) to each timestamp).
I believe the simplest way might be using module:
final long MILLIS_PER_DAY = 1000*60*60*24;
long time1 = 1546258765000L; // (Mon 31 December 2018 13:19:25)
long time2 = 1546005915367L; // (Fri 28 December 2018 15:05:15)
// Set both times to 0:00:00
time1 -= time1 % MILLIS_PER_DAY;
time2 -= time2 % MILLIS_PER_DAY;
And then
TimeUnit.DAYS.convert(time1 - time2 , TimeUnit.MILLISECONDS))
should give you the desired result.
Convert millis to LocalDateTime then calculate the Duration:
LocalDateTime start = LocalDateTime
.ofInstant(Instant.ofEpochMilli(1546005915367L), ZoneId.systemDefault())
.truncatedTo(ChronoUnit.DAYS);
LocalDateTime stop = LocalDateTime
.ofInstant(Instant.ofEpochMilli(1546258765000L), ZoneId.systemDefault())
.truncatedTo(ChronoUnit.DAYS);
Duration duration = Duration.between(start, stop);
long dayDifference = duration.toDays();
Converts the given time duration in the given unit to this unit.
Conversions from finer to coarser granularities truncate, so lose precision. For example, converting 999 milliseconds to seconds results in 0.
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/TimeUnit.html#convert(long,%20java.util.concurrent.TimeUnit)
Use joda-time lib:
long time1 = 1546258765000L;
long time2 = 1546005915367L;
DateTime dateTime1 = new DateTime(time1);
DateTime dateTime2 = new DateTime(time2);
int hours = Hours.hoursBetween(dateTime2, dateTime1).getHours();
int days = hours % 24 == 0 ? hours / 24 : hours / 24 + 1;
System.out.println(days);
joda-time lib has method to calculate days between two timeļ¼but the result is not your want:
Days.daysBetween(dateTime1,dateTime2).getDays()
I have a Timestamp in this format: 1479912701805
If you check on
http://www.epochconverter.com/ you can see that date is
GMT: Wed, 23 Nov 2016 14:51:41.805 GMT
Now I need to shorten that long to
1479859200 which is 3 number shorter, I guess milisecs
From your data in example, you need to remove hours, minute and seconds from
the value first. Using the % will be enough.
Remove the remainder of the number of milliseconds of a day from this value.
l -= l% (1000*60*60*24);
A small example :
long l = 1479912701805l;
Calendar c = Calendar.getInstance();
c.setTimeInMillis(l);
System.out.println(c.getTime());
l -= l% (1000*60*60*24);
c.setTimeInMillis(l);
System.out.println(c.getTime());
Wed Nov 23 15:51:41 CET 2016
Wed Nov 23 01:00:00 CET 2016
PS : The remaining hours is the time zone ;)
1479912701805
1479859200000
Then, just divide this by 1000 to remove the 3 first digit
divide by 1000 to get secs? linked site is recognizing "long" (milisecs) timestamps and shows: Assuming that this timestamp is in milliseconds, then calculates after /1000 division, so both 1479859200 and 1479859200000 are same date on this site
note that your examples are 1479912701805 and 1479859200 - same date only, but not hour/min/secs
there is also method:
long timeMillis = 1479859200000;
long timeSecs = TimeUnit.MILLISECONDS.toSeconds(timeMillis);
which is of course dividing by 1000, but you may find other TimeUnit methods useful
I'm using the following SimpleDateFormat
DateFormat dateFormat = new SimpleDateFormat("dd/MMMMM/yyyy:HH:mm:ss.SSSSS");
And then reading in my timestamp with, where timeStamp is a string like this 29/May/2013:09:12:06.80652 and this.timestamp is a Date
this.timestamp = dateFormat.parse(timeStamp);
I can't understand why, when I go to output timestamp and use it for timestamp comparison, the times are changed- given that date above, my output is
Timestamp before dateFormat: 29/May/2013:09:12:06.80625
Timestamp after dateFormat: Wed May 29 09:13:26 EDT 2013
I don't care about the EDT and other formatting, what I can't understand is how the time goes from 9:12:06 to 9:13:26.
Thanks!
Your format is taking microseconds as milliseconds so your 80625 is converted in minutes and seconds (1min20sec = 80000ms).
You should truncate microseconds and flush 3 least significant numbers.
This will work :
DateFormat oDateFormat = new SimpleDateFormat("dd/MMMMM/yyyy:HH:mm:ss.SSS");
String sDate = "29/May/2013:09:12:06.80625";
long lMicroseconds;
// Computing milliseconds from microseconds since it the number of digits can change
lMicroseconds = Long.valueOf(sDate.substring(sDate.indexOf('.') + 1,sDate.length()));
sDate = sDate.substring(0,sDate.indexOf('.')) + "." + (lMicroseconds / 1000);
System.out.println(oDateFormat.parse(sDate));
You forgot to take the milliseconds into account, and 80625 milliseconds are more or less 80 secondes, or 1 minute and 20 seconds.
9:12:06 + 1:20 => 9:13:26
If you want to handle them, you may take a look at the Calendar and TimeUnit API.
80625 is exactly 1min and 20 seconds more. So this is how you get the change, it just adds the milliseconds.
I have Java time (ms since 1/1/1970 UTC) and would like to write that time to a csv file, so that Excel can correctly interpret and format it. I understand, that excel uses "serial date time" as a format - that is a floating point number, where the integer part gives the number of days since 1/1/1900 and the decimal part gives fractions of a day.
I fail to understand timezone and daylight saving time handling in this.
This page says that the excel epoch (1/1/1900) is based on the local (=computer creating the Excel file?) timezone. This means that a serial date does not indicate a unique instant in time without the info which computer timezone created it. Not what I would have chosen, but OK.
Now accepting this, I believed I could convert Java time to Excel serial date by the following Java code (nb: I'm in Zurich, CET timezone):
private static final long ONE_HOUR= 60L * 60 * 1000;
private static final long ONE_DAY = 24 * ONE_HOUR;
private static final long excelEpoch;
static{
Calendar cal;
cal = Calendar.getInstance(TimeZone.getTimeZone("Europe/Zurich"));
cal.set(Calendar.YEAR, 1900);
cal.set(Calendar.DAY_OF_YEAR, 1);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
excelEpoch = cal.getTimeInMillis();
}
private static String formatForExcel(long time){
return ""+(time-excelEpoch)/(double)ONE_DAY;
}
Using this I can print out a few times:
public static void main(String[] args) {
String sep = "\t"; // csv field separator
SimpleDateFormat fmt = new SimpleDateFormat("HH:mm:ss d/M/yyyy");
fmt.setTimeZone(TimeZone.getTimeZone("Europe/Zurich"));
System.out.println("Time in ms since 1/1/1970 UTC"+ sep + "Time as string" + sep + "Excel serial" + sep + "Excel serial formatted by excel");
long startTime = 1332630000000L; // 25/3/2012 00:00 CET , shortly before change from winter time to DST
for (long t = startTime; t < startTime + 4*ONE_HOUR; t+=ONE_HOUR) {
System.out.println(t + sep + fmt.format(new Date(t)) + sep + formatForExcel(t) + sep + formatForExcel(t));
}
}
Which returns
Time in ms since 1/1/1970 UTC Time as string Excel serial Excel serial formatted by excel
1332630000000 00:00:00 25/3/2012 40991.0 40991.0
1332633600000 01:00:00 25/3/2012 40991.041666666664 40991.041666666664
1332637200000 03:00:00 25/3/2012 40991.083333333336 40991.083333333336
1332640800000 04:00:00 25/3/2012 40991.125 40991.125
Note that the change from winter time to DST happens in those hours (check second column, hour 2 is missing).
Now comes the confusion. If I paste this in excel, and for the last column choose "Format cells..." and then "Time" (any of the formats), it prints:
Time in ms since 1/1/1970 UTC Time as string Excel serial Excel serial formatted by excel
1332630000000 25.03.2012 00:00 40991 0:00:00
1332633600000 25.03.2012 01:00 40991.04167 1:00:00
1332637200000 25.03.2012 03:00 40991.08333 2:00:00
1332640800000 25.03.2012 04:00 40991.125 3:00:00
Note, that excel in formatting the serial date, does not change to DST. So this is not wallclock time.
Long story short:
How should I convert Java time to Excel so that it just works?
I suspect that Excel doesn't really take the time zone into account. I suspect it's really just treating it as a "local time" where every conceivable date/time is valid. (A "local instant" in Joda Time parlance, I believe - although I don't know how widely that's used.)
I suspect there's no way of representing a specific instant in time, and that instead you should:
Take whatever date/time you want to represent as a local time (e.g. "25th March 2012, 3am")
Put that into a Calendar which is set to use UTC
Take the millis from calendar.getTime().getTime()
Subtract the "Excel epoch" value of 1900-01-01T00:00:00Z (again, obtain via a calendar which is set to UTC)
Divide by "millis per day"
Now there's also an oddity with Excel in terms of its handling of dates before March 1st 1900, but hopefully that won't bite you.
Convert floating point "serial date/time" to "mills since 1970/1/1"
Note: daysFrom1900to1970 works for google spreadsheet dates, but might need slight adjustment for excel
int daysFrom1900to1970 =365*70 + 19; // Or maybe =365*70 + 17 But 19 worked.
int millisPerDay = 1000 * 60 * 60 * 24;
long millisSince1970 = (long) ((timeToSend.doubleValue() - daysFrom1900to1970) * millisPerDay );
Calendar dateTimeToSend = Calendar.getInstance();
dateTimeToSend.setTimeZone(TimeZone.getTimeZone("GMT"));
dateTimeToSend.setTimeInMillis(millisSince1970);
System.out.println("timeToSend:"+ new SimpleDateFormat("yyyy.MM.dd HH:mm:ss z").format(dateTimeToSend.getTime()));
I have a gps time in the database,and when I do some query,I have to use the java.util.Date,however I found that I do not know how to change the gps time to java.util.Date.
Here is a example:
The readable time === The GPS time
2010-11-15 13:10:00 === 634254192000000000
2010-11-15 14:10:00 === 634254228000000000
The period of the two date is "36000000000",,obviously it stands for one hour,so I think the unit of the gps time in the db must be nanosecond.
1 hour =3600 seconds= 3600*1000 milliseconds == 3600*1000*10000 nanoseconds
Then I try to convert the gps time:
Take the " 634254228000000000" as example,it stands for("2010-11-15 14:10:00");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ");
Date d = new Date(63425422800000L);
System.out.println(sdf.format(d));
The result is
3979-11-15 13:00:00+0000.
Of course it is wrong,then I try to calculate :
63425422800000/3600000/24/365=2011.xxx
So it seems that the gps time here is not calcuated from Epoch(1970-01-01 00:00:00+0000).
It maybe something like (0001-01-01 00:00:00+0000).
Then I try to use the following method:
Date date_0=sdf.parse("0001-01-01 00:00:00+0000");
Date d = new Date(63425422800000L);
System.out.println(sdf.format(d.getTime() + date_0.getTime()));
The result is:
2010-11-13 13:00:00+0000. :(
Now I am confusing about how to calculate this gps time.
Any suggestion?
1 millisecond = 1 000 000 nanoseconds
so...
1 hour =3600 seconds= 3600*1000 milliseconds == 3600*1000*10000000 nanoseconds
Notice that GPS time is 15 seconds ahead from UTC :
gps-time-representation-library
There are other time and date systems as well; for example, the time scale used by the satellite-based global positioning system (GPS) is synchronized to UTC but is not adjusted for leap seconds.
Quoted from : Java Util Date API
GPS time was zero at 6-Jan-1980 as opposed to Epoch which was zero at 1970-01-01 00:00:00+0000
Here is the simple Java code I used to convert GPS time (ms) to Java Date:
BigInteger gpsTime = new BigInteger("973865400000");
GregorianCalendar calendar =
new GregorianCalendar(1980, Calendar.JANUARY, 6, 0, 0, 0);
long gpsDiff = calendar.getTimeInMillis(); // gps offset to a
Date javaDate = new Date(gpsDiff + gpsTime.longValue());
System.out.println("Java Date: " + javaDate);
// prints: Java Date: Mon Nov 15 14:10:00 EST 2010