Edit:
lets say I have the date 11.11.2016 for what I want the Unix timestamp.
At the moment I just use
final int start = (int) ((System.currentTimeMillis() - 24 * 60 * 60 * 1000 * 5) / 1000L);
for 10.11.2016 it would be
final int start = (int) ((System.currentTimeMillis() - 24 * 60 * 60 * 1000 * 6) / 1000L);
But it looks somehow so basic :)
Is there maybe a better solution? I couldn't find any function in Date nor LocalTime.
Thanks!
It only makes sense to convert a "date" to epoch seconds if you specify a time of day and a time zone that you want the epoch seconds for.
Otherwise, the conversion is undefined, because a "date" is a 24-hour period (usually) in a specific timezone, whereas a unix timestamp is a number of seconds since 1970-1-1 00:00:00 UTC.
LocalDate.of(2016, 5, 10)
// e.g. LocalTime.of(12, 0) or .atStartOfDay()
// - *not* midnight, in general, since this does not always exist.
.atTime(someLocalTime)
// e.g. ZoneId.of("UTC")
.atZone(someTimeZoneId)
.toEpochSecond();
Related
I came across following formula in which localTimeDay is being retrieved from TimeStamp and Timezone:
long localTimeDay = (timeStamp + timeZone) / (24 * 60 * 60 * 1000) * (24 * 60 * 60 * 1000);
I am not able to understand what is the meaning of Local Time Day and how this formula "magically" converts based on TS and TZ.
timestamp is a count of milliseconds since the epoch of Jan 1, 1970 at 00:00 UTC.
timeZone is the offset in milliseconds from UTC. It may be positive, negative or zero. It must have its sign reversed, though, for the formula to work, as far as I can see: an offset of +01:00 should be given as minus 3 600 000 milliseconds. When I add the offset, I get a different point in time where the date and time of day in UTC is the same as the original date and time of day at that UTC offset.
Dividing by 24 * 60 * 60 * 1000 converts from milliseconds to days since the epoch. Any fraction of a day, that is, any time of the day, is discarded.
Multiplying by 24 * 60 * 60 * 1000 converts back from days to milliseconds. Since the time of day was discarded, we now have the time at 00:00 UTC on that day.
So it’s a way of converting from a point in time at some UTC offset to the date alone represented in UTC.
It’s not code that you would want to have in your program. You should leave such conversions to proven library methods. It might however be code that could be found inside such a tested and proven library.
Edit: Why do I believe that the sign of the offset has been reversed? Couldn’t it be the opposite conversion, from UTC to local? The variable name localTimeDay seems to suggest this? The division and multiplication only works in UTC. Since the epoch is at 00:00 UTC, the formula necessarily gives you the start of a day in UTC, it cannot give you the start of a day at any non-zero offset. Therefore I figure that the conversion must be from local to UTC.
How to do in your code
Here’s a nice way of doing the same conversion using java.time, the modern Java date and time API
// The point in time given in UTC
Instant time = Instant.parse("2020-04-23T05:16:45Z");
// The UTC offset, +02:00
ZoneOffset offset = ZoneOffset.ofHours(2);
ZonedDateTime startOfDayInUtc = time.atOffset(offset)
.toLocalDate()
.atStartOfDay(ZoneOffset.UTC);
System.out.println(startOfDayInUtc);
long epochMillis = startOfDayInUtc.toInstant().toEpochMilli();
System.out.println(epochMillis);
Output:
2020-04-23T00:00Z
1587600000000
We can check that it gives the same result as your code line:
long timeStamp = time.toEpochMilli();
// Reverse sign of offset
long timeZone = -Duration.ofSeconds(offset.getTotalSeconds()).toMillis();
long localTimeDay = (timeStamp + timeZone) / (24 * 60 * 60 * 1000) * (24 * 60 * 60 * 1000);
System.out.println(localTimeDay);
System.out.println("Agree? " + (localTimeDay == epochMillis));
1587600000000
Agree? true
Edit: you asked in a comment:
I still have this doubt: There is fixed number of millis that have
elapsed since Jan 1 1970, so every country should get same number.
Does localTimeDate mean "date for my country" or to the country where
this data came from? For example: Country-A , Country-B; they will see
same millis since Epoch. Suppose data processing is happening in
Country-A and origin of data is Country-B. So when we say
"localTimeDate" , does it pertain to Country-A or Country-B.
It will work for both countries. It all depends on the timeZone value that enters into the formula. If that is the UTC offset for country A (sign reversed), the conversion will be from country A time to UTC date. If it’s country B’s offset, the conversion will be from country B time. And you are fully correct, you will get two different dates if it’s not the same date in countries A and B, which could easily be the case.
I am trying to convert code from Python to Java. I need to rewrite the timedelta function in Java. Here is the code in Python:
def timeDate(date):
return (timedelta(seconds=date * 3600 % 86400))
Does anyone have any idea on how to make a function that acts the same?
double hours = 21.37865107050986;
long nanos = Math.round(hours * TimeUnit.HOURS.toNanos(1));
Duration d = Duration.ofNanos(nanos);
// Delete any whole days
d = d.minusDays(d.toDays());
System.out.println(d);
This prints:
PT21H22M43.143853836S
Which means: a duration of 21 hours 22 minutes 43.143853836 seconds.
Assumptions: I understand that you want a duration (the docs you link to say “A timedelta object represents a duration”). I have taken date to be a floating-point number of hours, and your modulo operation lead me to believe that you want the duration modulo 1 day (so 26 hours should come out as a duration of 2 hours).
The Duration class in Java is for durations, hence is the one that you should use. It doesn’t accept a floating point number for creation, so I converted your hours so nanoseconds and rounded to whole number. For the conversion I multiplied by the number of nanoseconds in 1 hour, which I got from the call to TimeUnit (this gives clearer and less error-prone code than multiplying out ourselves).
The code above will tacitly give incorrect results for numerically large numbers of hours, so you should check the range before using it. Up to 2 500 000 hours (100 000 days or nearly 300 years) you should be safe.
Please note: if date was a time of day and not a duration, it’s a completely different story. In this case you should use LocalTime in Java. It’s exactly for a time of day (without date and without time zone).
nanos = nanos % TimeUnit.DAYS.toNanos(1);
LocalTime timeOfDay = LocalTime.ofNanoOfDay(nanos);
System.out.println(timeOfDay);
21:22:43.143853836
Link: Documentation of the Duration class
As far as I know, Java doesn't have a built in DeltaTime function. However you can easily make your own.long startTime;
long delta; public void deltaTime(){ long currentTime = System.currentTimeMillis(); delta = currentTime - startTime;}
Whenever you want to start your DeltaTime timer, you just do time = System.currentTimeMillis;. This way, the variable "delta" is the amount of time between when you started the DeltaTime timer and when you end it using ClassNameHere.deltaTime();.
private static LocalTime timeDate(double d) {
//converts into a local time
return LocalTime.ofSecondOfDay((long)(d*3600%86400));
}
Input (d):
36.243356711275794
Output:
21:22:43
I got strange java casting problem today coming from such code
new Date(System.currentTimeMillis() - 1000 * 60 * 60 * 24 * 31)
This is supposed to give date 31 days before now, but returns date 16 days after. It obviously happens because
1000 * 60 * 60 * 24 * 31
is evaluated as Integer and overflows.
new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 31)
works as expected
I think java should cast whole expression to Long because first operand is Long System.currentTimeMillis() but it's not happening here for some reason I don't understand. Is there some exception about hardcoded constants to be int ?
It’s all been said, but I thought it deserved to go into an answer. Use the ZonedDateTime class with ZoneId.
ZonedDateTime aMonthAgo = ZonedDateTime.now(ZoneId.of("Indian/Comoro")).minusMonths(1);
Output on my computer just now (April 11):
2018-03-11T19:57:47.517032+03:00[Indian/Comoro]
I subtract a month, so that means 28, 29, 30 or 31 days depending on the month I’m in and the number of days in the previous month. If you want 31 days unconditionally, you can have that, of course:
ZonedDateTime thirtyoneDaysAgo
= ZonedDateTime.now(ZoneId.of("Indian/Comoro")).minusDays(31);
Since there were 31 days in March, the result is the same in this case. It won’t always be.
I am using and recommending java.time, the modern Java date and time API. It’s so much nicer to work with and much less error-prone than the outdated Date class.
What went wrong in your code?
It’s about operator precedence. 1000 * 60 * 60 * 24 * 31 consists of int values. Yes, integer literals have type int unless they have the L suffix. Because multiplication is carried out before subtraction (as you had already expected), the result is an int too, but it overflows because the result would be greater than the maximum number that an int can hold. Unfortunately Java doesn’t inform you of the overflow, it just gives you a wrong result, here -1616567296, about -19 days. When subtracting these, you get a date and time about 19 days into the future.
As a habit, use parentheses, the L suffix, and underscore-grouping for readability.
( System.currentTimeMillis() - ( 1_000L * 60L * 60L * 24L * 31L ) )
If you wanted to be made aware of overflow, you may use Math.multiplyExact() for your multiplications (since Java 8). Fortunately, the modern library classes save you completely from multiplying. And signal any overflow.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Math.multiplyExact() documentation
I have a piece of code that is used to calculate the number of days between two Date objects, and in most instances, it works fine.
However, if the date range between the two objects includes the end of March, the result is always 1 less than it should be. e.g March 31 2014 - March 29 2014 = 1, whereas it should be 2.
I understand that this is due to the fact that March has 30 days of 24 hours and 1 day of 23 hours due to DST, which is the cause of the value being 1 less.
However, I am not sure the best way to account for the missing hour.
// This was what I have initially
int numDays = (int) ((dateTo.getTime() - dateFrom.getTime()) / (1000 * 60 * 60 * 24));
// I have tried rounding, since it should have 23 hours left over, but it didn't actually work.
int numDays = (Math.round(dateTo.getTime() - dateFrom.getTime()) / (1000 * 60 * 60 * 24));
Any help/pointers would be greatly appreciated.
I am and have to use Java 7 and I am not able to use Jodatime unfortunately.
Your second example is very close. Your parentheses for Math.round() only surround the subtraction, though, so since that's already an integer (well, a long really), nothing happens, and then you divide. The other problem with your second bit of code is that you are doing integer division which always truncates the part after the decimal point. Try this:
long numDays2 = Math.round((dateTo.getTime() - dateFrom.getTime()) / (1000.0 * 60 * 60 * 24));
(As indicated, I changed the Math.round() parens, and made it floating point division by making the divisor a double.)
As indicated by the comments, though, this is a hack. In particular, it will tell you that there are two days between 6AM March 5 and 8PM March 6. It's probably not really what you want. Try this on for size instead:
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
Calendar cal = Calendar.getInstance();
cal.setTime(fmt.parse("2014-03-29"));
long start = cal.getTimeInMillis();
start += cal.getTimeZone().getOffset(start);
cal.setTime(fmt.parse("2014-03-31"));
long end = cal.getTimeInMillis();
end += cal.getTimeZone().getOffset(end);
System.out.println((end - start)/86400000.0);
Is it ugly? Yes. Is it weird? Yes. Does it work? Yes (I think so). Note that I'm providing a double as a result; you can apply any rounding you want to this result.
I am using Calendar on a Samsung Note. If I get a new instance of Calendar with Calendar.getInstance() and then call getTimeInMills() without doing anything else I get 1403732346277, which apparently is some value in the very far future.
I need to get a unix style timestamp. Is there some other preferred way to do this? Or some reason why the Calendar is returning this value (i.e. a standard adjustment I can make)?
Unix time represents the number of seconds from the epoch. As the name implies, getTimeInMillis() will return the number of milliseconds from the epoch. You need to divide your milliseconds by 1000 to get unix time.
long unixTime = Calendar.getInstance().getTimeInMillis() / 1000;
getTimeInMillis() returns you the time difference from Jan 1, 1970 with the calendar time in milliseconds.
Here is the calculation:
1403732346277 ms = 1403732346.277 seconds
1403732346.277 s = 389925.6517... hours
389925.6517 h = 16246.90 days
16246.90 days = 44.512 years (simple calculation: I divided by 365 just to get an approx idea. There are leap years in between.)
If you find the difference of current date from Jan 1, 1970, it is 44 years and ~6 months. So it seems to be giving you right time in milliseconds.
Or some reason why the Calendar is returning this value (i.e. a standard adjustment I can make)?
The java.util.Calendar API stores dates and times as the number of milliseconds that have elapsed from epoch (January 1, 1970 midnight UTC).
The number you got from Calendar.getInstance() - 1403732346277 - is what you'd expect. It's the number of milliseconds from epoch up to today at the exact time you called Calendar.getInstance().
If you want to extract more human-readable date/time information from that Calendar object, you can do something like:
Calendar cal = Calendar.getInstance();
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH);
int day = cal.get(Calendar.DAY_OF_MONTH);
int hour = cal.get(Calendar.HOUR_OF_DAY);
int minutes = cal.get(Calendar.MINUTE);
I need to get a unix style timestamp. Is there some other preferred way to do this?
As this post points out, you can get UNIX epoch by:
long unixTime = System.currentTimeMillis() / 1000L;