I am getting the current time in epoch. How can I add 1 month in future?
Date date = new Date();
int epoch = date.getTime();
Datatype for epoch - integer($int64)
To be precise: I want to add 30 days from current time.
I am using a tool that allows Groovy and Java code to be embedded. I used Date class because I can easily import java.text.DateFormat; and import java.text.SimpleDateFormat;. The tool that I have doesn't support Instant.
Since Java 8, use java.time for time usage
As epoch seconds, adding 30 days:
Instant.now().plus(30, ChronoUnit.DAYS).getEpochSecond()
As epoch milliseconds, adding 30 days:
Instant.now().plus(30, ChronoUnit.DAYS).toEpochMilli()
You don’t want to use Date, use date time API.
Instant.now().plus(30, ChronoUnit.DAYS)
Here's how I'd do it:
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, 30);
long epoch = calendar.getTimeInMillis();
System.out.println(epoch);
Result:
1606785580218
This is milliseconds. You can divide by 1000 to get the version in seconds. NOTE: The seconds version will fit in an int whereas the milliseconds version requires a long. So it's OK to do this if you want the seconds version in an int:
long epoch = ...
int epochSeconds = (int)(epoch / 1000);
BTW, Unix time (Epoch time, POSIX time) is defined as the number of seconds since 1 January 1970 UTC. Some systems will return the value in milliseconds to provide more accuracy, but such a value is officially a fractional Epoch time multiplied by 1000.
So far all answers are wrong.
That's because what you want is impossible.
You're mixing entirely incompatible concepts. You're asking to add 1 entity that is devoid of timezone and political meaning ('epoch-millis', which explicitly means: No timezone info!) with a concept that cannot be nailed down as meaning anything particular unless you supply timezone and era.
You cannot add a month to an epoch milli. Not because java doesn't let you, or because it is hard to program. You can't do it for the same reason you cannot point at the corner in a circle. It's literally impossible, by definition.
'epoch millis' are a concept that is fundamentally about a moment in time. Things like 'when the sun flared up'. "When I clapped my hands together just now". This concept is best represented in java by an instance of java.time.Instant. It is also represented by a java.util.Date, which is funny, because this is nothing like a Date, and indeed, j.u.Date is an utterly stupid name, and the authors have belatedly realized this, which is why (almost) all of the methods it has are marked #Deprecated with a note describing that Date's very name is a total lie. j.u.Date does not represent dates.
A month, that's an entirely different can of worms. There's nothing solid about a month. It could be 28 days. 30 days. 31 days. 30 days and an extra second tossed in. It could be a month that doesn't even exist, or is only 11 days (when political areas switch timezones, you can get some really bizarre things happening).
So, how do you add 'a month' to any instant in time?
You can't. It's not possible. You'd have no idea what to add, because there is no way to figure out if it's 28 days, 29, 30, 31, let alone leap seconds and era weirdness (recently, samoa switched to the other side of the dateline, and as a consequence, their december was only 30 days. The famous 'october revolution' that introduced communism to russia happened in november, at least as far as the entire world (except the russians) were concerned, because only the russians were on the julian calendar where it was still october. As part of the whole 'communism will take over the world!' scheme one of the very first things they did was get on the gregorian same as the rest of the world, and as a consequence, this date does not exist, AT ALL, in russian history: 1 through 13 feb 1918. They just. . were skipped. One day you wake up in moscow, walk outside, ask somebody: Hey, what date is it (though probably in russian), and they say: Why, 31st of January, comrade. Next day you repeat that exercise and now it is February 19th. So, february 1918 in russia was 15 days long.
See why 'please add 1 month' is just not a thing that could possibly be done unless you tell me when and where? If you tell me 'in russia', then I still don't know if I add 15, or 31, or 30, or 29, or 28. If you tell me 'Februari, in 1918', well, in the rest of the world, februari was 28 days. Only in russia it was 15.
Now, adding 'a month' to some human-oriented date/time construct, such as 'well, right now, in amsterdam', ah, that works: "THIS month, the month it is right now, in amsterdam", that is a question that has an answer. But, 'epoch millis' is java-ese for: "An instant in time, devoid of any and all geographical information", and by missing geo info it is also impossible to know when that is relative to any timezone, and therefore, utterly impossible.
So, what CAN you do? Well, many things, but first you need to figure out what you want to do, and only then can somebody tell you how to do it:
I just want to add what feels like an average month, and end up with epoch-millis. Okay, then just add 2.629.800.000, which is a rough estimate (that's about 30.4375 days, which is roughly the average length of a month. I have no idea what possible purpose this would serve, but it's surely a better plan than adding 30 days, or 31 days, or 28 days.
I want to first translate this epoch-millis into a time as humans would say it (in turns of year, month, day, hour, minute, and second), and then just increment the month value by 1, and leave it at that, in e.g. a ZonedDateTime object. Okay, then first figure out which timezone you want, then turn your epoch-millis into a ZonedDateTime, and THEN we've arrived at a point where 'add a month to this please' even makes sense, so now we can do that: .plusMonths(1), voila.
Same as previous, but then convert that back to epoch millis. Okay, well, do the same thing, and call .toInstant() at the end, and toEpochMillis() on that.
Most other ideas boil down to: Your question makes no sense and cannot be answered.
NB: The above all use the java.time packages. All other options (java.util.Date and java.util.Calendar are broken and unwieldy; generally attempting to do this or any other date-related job in those APIs will either be impossible, will give wrong answers, or there is a way but it is hard to figure out how and the resulting code will be hard to maintain and hard to follow. Why would you voluntarily punch yourself in the face? Why would you voluntary use crap APIs? Don't do that.
Related
How would one calculate a number of days in 1582. Yes, that is the year of introduction of the Georgian Calendar (in some countries). I assume October 1582 should not have 31 days as some of the dates never existed.
Yet when I tried Joda Time (Java/Groovy) it says 30 days:
LocalDate start = new LocalDate("1582-10-01");
LocalDate end = new LocalDate("1582-10-31");
println Days.daysBetween(start, end).getDays();
Same for SQL
-- PostgreSQL
SELECT DATE_PART('day', '1582-10-31'::date - '1582-10-01'::timestamp);
-- MSSQL
SELECT DATEDIFF(dd, '1582-10-31', '1582-10-01');
So is there some agreement/specification to actually treat 1582-10-14 as if it would actually exist? Or is there some easy way to calculate correct diff for year 1582 and earlier?
I have not used Java in many years, but I am familiar with dealing with several calendars in other languages. From the "Key Concepts" subtab of the "Documentation" tab of the Joda Time website we find the "Chronology" page which states
The default chronology in Joda-Time is ISO. This calendar system is
the same as that used by business in the majority of the world today.
The ISO system is unsuitable for historical work before 1583 as it
applies the leap year rules from today back in time (it is a proleptic
calendar). As a result, users requiring a more historically accurate
calendar system are forced to think about their actual requirements,
which we believe is a Good Thing.
Proleptic means that from a known day and date that virtually everyone agrees about, such as the Meter Convention having been signed in Paris on 20 May 1875, the rules of the calendar are applied backward to find any date desired, even if it is before the calendar was created.
As for computing the interval in one calendar, such as the Julian calendar, to a date in a different calendar, such as the Gregorian calendar, a common approach is to convert them both to a count-of-days from a chosen epoch, such as the modified julian date, which counts from midnight universal time at the beginning of November 17, 1858. Then one simply subtracts one day count from the other to find the number of days between them. A quick glance at the Joda Time documentation did not show any facility for computing a day count.
I am currently not set up to program in Java. Ole V.V. comment about using the Gregorian-Julian chronology of Joda-Time seems useful, but I have not tried it:
LocalDate first = new LocalDate(1582, 10, 1, GJChronology.getInstance());
LocalDate last = new LocalDate(1582, 10, 31, GJChronology.getInstance());
int countOfDaysDiff = Days.daysBetween(first, last).getDays();
System.out.println(countOfDaysDiff);
Output according to Ole V.V.:
20
I think I will go ahead and close with that both answers are probably correct. October 1582 did and didn't have 31 days. I mean that 14th October didn't exist (as in no one was born on that day in Gregorian Calendar) and for the purpose of accounting all debts were pushed by ten days. So I guess the only way is to manually count days and don't use any libraries for that.
When establishing Gregorian Calendar it was said that:
we direct and ordain:
that ten days shall be removed from the month of October of the year 1582
But also:
But in order that nobody suffers prejudice by this our subtraction of ten days, in connection with any annual or monthly payments, the judges in any controversies that may arise over this, shall by reason of the said subtraction add ten days to the due date for any such payment.
Source: https://en.wikisource.org/wiki/Translation:Inter_gravissimas
This test normally passes all year round when the there is no lost hour or gained hour to account for. But right now it's being a nuisance. We're validating that the expiration date, getExp(), minus 7 days, is within 10 milliseconds of the issue date, getIss(). Since the exp and iss values are generated right after each other 10 milliseconds is a perfectly acceptable delta to expect the values to be between.
But now they're understandably an hour off when it looks a week into the future when the Java date code calls setExp() after initializing a new JWT Claim.
Assertion / test code:
assertThat(claim.getExp()).isCloseTo(new DateTime(claim.getIss()).plusDays(7).toDate(), 10);
In english this reads: assert that the claim's expiration date is within 10 milliseconds of the claim's issue date + 7 days.
An immediate fix is to add an hour's worth of milliseconds to the allowed delta but I was curious to see if there was a better solution.
EDIT: I believe I found the issue. We initialize claim issue date and claim expiration date using ZonedDateTime.now():
Claim claim = new Claim();
claim.setIss(Date.from(ZonedDateTime.now(ZoneId.of("UTC")).toInstant()));
claim.setExp(Date.from(ZonedDateTime.now(ZoneId.of("UTC")).plusDays(7).toInstant()));
But when we validate with JODA time we assume our local rules for daylight savings time. This obviously causes an issue with GMT DST vs. American DST rules.
EDIT2: The fix involved 2 words and updating the unit test to respect UTC:
assertThat(claim.getExp()).isCloseTo(new DateTime(claim.getIss(), DateTimeZone.UTC).plusDays(7).toDate(), 10);
Your only two solutions are:
Change your reporting so that, instead of being based on local time, is uses UTC (ie, epoch unix time). This is the preferable solution from a tech point of view since it's a worldwide standard including most shared servers and data sources; no DST to worry about; and you can still have your reports calculate local time.
Alternatively, to find or add a reliable 'dateadd'-type function that take Daylight Savings into account.
I've always been surprised that all platforms don't have that functionality built-in. Granted, DST has a confusing, ever-evolving set of rules that are region-specific (by continent, country, and is some areas by "state" or even "county") ...but still.
Currently, in most of North America, DST:
Begins on the 2nd Sunday of March. ("Spring Forward" so clocks change from 01:59 to 03:00)
Ends on the 1st Sunday of November. ("Fall Back" from 01:59 to 01:00)
Windows API has functionality for calculating whether DST is in effect but really, no application should allow an application to display, for example in North America: "Sunday March 11, 2018 02:30:00" because that time doesn't exist.
...still, #1 is your preferable solution because accuracy and standardization are more straightforward.
Given an epoch time: eg (1513213212) I should get 1 since its 1 am right now UTC. How would I go about converting it into the hour of the day? Is it possible to do it just using math (division, mod)?
It would be close to impossible to do it by using maths only. (Leap year and all). It's better to use established APIs which will do all the hard work.
You can use following method to do this.
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(1513213212* 1000L);
cal.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(cal.get(Calendar.HOUR));//12 hour clock
System.out.println(cal.get(Calendar.HOUR_OF_DAY));//24 hour clock
Use java.time, the modern Java date and time API also known as JSR-310:
LocalTime timeOfDay = Instant.ofEpochSecond(1513213212L)
.atOffset(ZoneOffset.UTC)
.toLocalTime();
System.out.println(timeOfDay);
int hourOfDay = timeOfDay.getHour();
System.out.println(hourOfDay);
This prints:
01:00:12
1
Even if you just wanted to do the math, I would still prefer to use standard library methods for it:
long epochSeconds = 1513213212L;
// convert the seconds to days and back to seconds to get the seconds in a whole number of days
long secondsInWholeDays = TimeUnit.DAYS.toSeconds(TimeUnit.SECONDS.toDays(epochSeconds));
long hourOfDay = TimeUnit.SECONDS.toHours(epochSeconds - secondsInWholeDays);
System.out.println(hourOfDay);
This too prints 1.
Your intention was “Given an epoch time: eg (1513213212) I should get 1 since it’s 1 AM right now UTC.” Which of the above code snippets in your opinion most clearly expresses this intention? This is what I would use for making my pick.
While MadProgrammer is surely correct in his/her comment that date and time arithmetic is complicated and that you should therefore leave it to the date and time API, I believe that this is one of the rare cases where not too complicated math gives the correct answer. It depends on it being safe to ignore the issue of leap seconds, and if going for the math solution, you should make sure to check this assumption. Personally I would not use it anyway.
I have a datepicker where the user selects a date and then a checkbox on what type of period he wants to get the date from. For example:
User selects the 1. of November and selects the checkbox "Month" in this case the end date will be increased by 1 and even if this sound simple enough its slowly starting to annoy me alot!
The problem is that Java doesnt have a great date object that works for this kind of thing so i thought that i would use Calendar but it isnt easy to increment a calendar date take for instance the following example:
endDate.set(startDate.YEAR, startDate.MONTH+1, startDate.DATE);
in theory this would increment the month by one being one larger than the start date. This works in about 90 % of the months EXECPT from December if you increase the month by 1 in December then the integer month return 13 same thing happens for startDate.DATE; and startDate.Year;
My question is isnt there an easier way to do this? i could make a ton of If sentences but i really think that it is kinda redundant.
Use add method of java.util.Calendar.
endDate.set(startDate.YEAR, startDate.MONTH, startDate.DATE);
if(some_condition) {
endDate.add(Calendar.MONTH, 1);
}
You can use Calendar.add() to add values to the calendar value, e.g. Calendar.add(Calendar.MONTH, 1) this adds one month and takes into account that January is after December.
The standard recomendation here is to look at Joda-Time (see here for more info). It's a much more consistent/capable API with none of the threading issues that plague the standard Java date/formatting APIs and as such is widely used and accepted.
In terms of what you want above, I would suggest something like:
LocalDate d = ...
LocalDate nd = d.plusMonths(1);
The above will correctly handle month/year rollovers.
I have seen way to many places where a method takes a long or an int to represent durations in either nanoseconds, milliseconds (most common), seconds and even days. This is a good place to look for errors, too.
The problem is also quite complex once you realize that you can mean for the duration to be a certain number of seconds, or an interval that fits the human perception of time better, so that a duration of 24 hours is always going to be the next day at the same "wall-clock" time. Or that a year is either 365 or 366 days depending on the date, so that a year from 28th of February is always going to be the 28th of February.
Why is there no distinct type to represent this? I have found none in either Java or .net
In .Net you can use the TimeSpan structure to represent a length of time.
For Java, take a look at Joda (an intuitive and consistent date/time library) and its Duration and Period classes. DateTime objects can handle addition and manipulation via these objects.
(answer changed to reflect the comments below re. the Period class)
It's not an easy problem. Maybe Joda-Time would be a useful library for you. It has a Duration class that can do what you are asking for.