For following code for java 8
1. System.out.println(LocalDateTime.now(Clock.systemDefaultZone()));
2. System.out.println(Instant.now(Clock.systemDefaultZone()));
Line 1 print current time by adding offset but line 2 print current time without adding offset.
I checked the source code of both and found that LocaDateTime.now(clock) return clock.instant() return time by adding offset but Instant.now(clock) not doing so.
Why it designed like this? Aren't we expecting same result in both case?
UPDATE: Instant has nothing to do with UTC in the timezone sense. It is related to UTC as a time standard only.
The major difference is the return type. They have different String representations because the types themselves have very different meanings.
Instant#now(Clock) returns Instant. An Instant is "[a]n instantaneous point on the time-line".
LocalDate#now(Clock) returns LocalDate. A LocalTime is "a description of the local time as seen on a wall clock".
As a result Instant#now(Clock) and LocalDate#now(Clock) mean very different things and naturally have different outcomes. The major thing they have in common is a name. Method names are dust. Refer to the types.
On a fixed Clock, both Instant.now(clock) and LocalDate.now(clock) will return constant values. The point of accepting Clock as a parameter is to be able to control things like the reference time or clock resolution.
Related
I want to use Instant type to put it to MySQL database (timestamp field). Unfortunately, when using POJO and Record#from(), jOOQ doesn't let me do that for some reason. I have the following to my gradle configuration:
forcedTypes {
forcedType {
name = "Instant"
types = "timestamp"
}
}
The code is being generated correctly, but doesn't work and gives me errors in runtime:
Data truncation: Incorrect datetime value: '2021-01-16 05:01:25.457+00:00' for column `test`.`messages`.`time_sent` at row 1
I tried to add my own converter and binder, but they don't seem to work if name is set in gradle config, as a warning appears during build. But without name I can't get jOOQ to generate Instant for timestamp field.
Is there a way to use Instant with SQL timestamp when using jOOQ's POJO?
MySQL's timestamp data type is a bit, well, idiotic.
It stores time as seconds since the epoch (jan 1st 1970, UTC, midnight), in a 32-bit integer. This has a few issues:
There is no room for milliseconds. Your Instant has .457 milliseconds and this needs to be stripped out, which is why JOOQ is refusing to do this; that's destroying data. I assume you don't care about those millis, but JOOQ doesn't know that. You can try to strip the millis out of the instant, if you must, JOOQ would presumably allow saving an Instant, if that Instant has the property that it the epochmillis that it wraps around is divisible by 1000 (has no millis part). Except, that was annoying, so at some point, eventhough it's stored as 32-bit seconds-since-epoch, the data type now also contains, separately, a fractional second, from 0 to 999999. Either you have an old version of MySQL or the underlying table structure that doesn't allow this, or JOOQ isn't aware that MySQL does at least support millis.
At 2038-01-19 03:14:07 UTC, your app explodes. That's it. That's the last timestamp representable by a MySQL TIMESTAMP object. We're less than 18 years removed from this. Therefore this datatype is effectively unusable, and you should use something else. (This may not sound believable to you. Peruse MySQL8's user manual §11.2.2 if you need some convincing, straight from the source). Java's core instant storage system doesn't suffer from the dreaded Y2K38, as java uses millis-since-epoch in 64-bit; we got a few billion years to go before that runs out of numbers.
Note that the printed message is a bit misleading. Instants are stored as milliseconds since epoch and do not have a timezone, that +00.00 in the printout suggests that it does. It doesn't - and thus the fact that mysql's TIMESTAMP type also doesn't isn't the problem.
Solutions
The best solution, by far, is to use a database engine that isn't broken like this. For example, try postgres.
A distant second solution is to peruse JOOQ issue #9665 where #lucaseder (core contributor of JOOQ; he's the genius doing the magic over there :P) says it doesn't work yet, but there's some code there you may be able to use.
Note that if you actually care about zones, this becomes a lot more complicated. There are 3 different ways to represent time; these are distinct and cannot be converted to each other without additional info and caveats; most tools incorrectly silently convert them anyway, and pain ensues when this happens. Thus, you may want to think about which of the 3 kinds of time you have here:
solarflares time: A moment time something happened or will happen, such as a solarflare. If some political entity decides to change timezone, it has no effect. The 'time until event occurs' / 'time since event occurred' goes up by 1 second every second no matter what happens with timezones. In java terms, java.time.Instant.
appointment time: I call my barber in Amsterdam and I have an appointment on Jan 5th, 2023, 14:00. You'd think this is like solarflares time, but, no. If the dutch parliament slams the gavel and adopts a law that the Netherlands will no longer observe daylight savings and will remain in summertime, then the moment that gavel comes down, the # of seconds until my appointment goes up by an hour (is it it down by an hour?). This is not exotic at all - see EU Directive 2000/84/EC - it is, in fact, likely. Solarflares time should not shift like this, and appointment time does. Best represented as year+month+day+hour+minute+second+millis+a full zone (which is Europe/Amsterdam, not silly useless stuff like +0800 or PST). In java terms, ZonedDateTime.
Alarmclock time: Just years, months, day, hour, minute, second. That's it - it doesn't represent anything particular but just the concept. If I set my alarm to wake me up at 08 in the morning and I take a trip across the pacific, the time until my alarm goes off should change drastically as I move timezones. In java terms, LocalDateTime and friends.
I'm assuming you have a solarflares time (for example, to track 'user X change their password at this time'). This answer assumes you meant that. If you did not, my advice would change a bit. Mostly that whole 'do not use mysql' thing would become even stronger: What you really want is the datatype TIMESTAMP WITH TIME ZONE such as postgres has.
After doing my research I wasn't able to find a method or data type that should be used for variable in order to store time in format of HH:MM, I did find methods to get this from a string like "14:15:10", but I think this is not the best way, as I'll need to add or subtract from time. I tried doing this as a double, but ran into following issue, when you have a time like 05.45 stored and add 0.15 (or 15 minutes) to it, the result is 05.60 where as with HH:MM format you'd expect it to be 06.00.
I'm looked through java documentation and still am, but can't seem to find any way to achieve this, closest I got to is date format like dd/mm/yyyy hh:mm:ss
Use Joda Time. It provides much better operations to do date/time manipulation than standard java dates. If you want to use internal JDK classes, use java.util.Date.
Since Java 8, you can use the new API for dates and times, including Instant, ZonedDateTime and LocalDateTime. This removes the use for the third party library Joda time. It also makes calculations more easy and correct. The advice below is a bit dated but still has some good points.
—————
What you definitely should NOT do is store them in your own custom format. Store the Long value that represents the Unix Epoch.
A DateTime is nothing more than a number to a computer. This number represents the amount of seconds (or milliseconds) since 1970-01-01 00:00:00 UTC. It's beyond the scope of this answer to explain why this date was universally chosen but you can find this by searching for Unix Epoch or reading http://en.wikipedia.org/wiki/Unix_time.
This also means there is NO timezone information stored in a DateTime itself. It is important to keep this in mind when reasoning about dates and times. For things such as comparing DateTime objects, nothing concerning localization or timezones is done. Only when formatting time, which means as much as making it readable to humans, or for operations such as getting the beginning of the day, timezones come into play.
This is also why you shouldn't store the time like 20:11:15 in a string-like format because this information is meaningless without timezone information. I will give you 1 example here: Consider the moment when the clock is moved back 1 hour, such as when moving away from daylight savings time. It just happened in a lot of countries. What does your string 02:30 represent? The first or the second one?
Calculations such as subtraction are as easy as doing the same with numbers. For example: Date newDate = new Date(date1.getTime() - date2.getTime());. Or want to add an hour to a date? Date newDate = new Date(oldDate.getTime() + 1000 * 60 * 60);
If you need more complex stuff then using Joda time would be a good idea, as was already suggested. But it's perfectly possible to just do even that with the native libraries too.
If there's one resource that taught me a lot about date/time, it would be http://www.odi.ch/prog/design/datetime.php
Java has java.sql.Time format to work with time-of-day values. Just import it and create variables.
import java.sql.Time;
//now we can make time variables
Time myTime;
Just saw it on https://db.apache.org/derby/docs/10.4/ref/rrefsqlj21908.html
The answer that is right for your case depends on what you want to do.
Are you using a RDBMS as your persistence engine?
If so, are you already working with legacy data formats or are you building a database from the ground up?
Are you simply storing this data, or will you be doing extensive date arithmetic and/or precedence calculations?
Are you in one time zone or do you need to work with time instants across many time zones?
All of these things are important and factor into your decision of how to represent your times and dates.
If your needs require a lot of date arithmetic (eg. determining days between dates) or sorting based on timestamps, then consider using a floating point date format. The advantage of using a numeric format for timestamps is that doing date arithmetic and comparison/sorting operations becomes trivial; you merely do simple arithmetic. Another advantage is that floats and longs are primitive data types. They do not need to be serialized, they are already extremely lightweight, and everything you need to use them requires no external dependencies.
The main disadvantage to using numeric formats for timestamps is that they are not human friendly. You'll need to convert them to and from a String format to allow users to interact. Oftentimes, this is worth the effort. See: How do I use Julian Day Numbers with the Java Calendar API?
I recommend that you consider storing timestamps as Julian Day Numbers (JDNs) or Modified Julian Day Numbers (MJDs). Both will represent dates and times to millisecond precision using an 8 byte float. Algorithms for converting to and from display formats for both of these are highly standardized. They confer all the advantages of using numeric dates. Moreover, they are defined only for GMT/UTC which means that your timestamps are already universalizable across time zones right out of the box (as long as you localize properly).
If you dont want the full date object, your best bet is to store it in a string, but I personally would still recommend date as it also contains a lot of convenient methods that will come in handy. You can just get the time as a whole from a date object and ignore the rest.
In terms of "storing" a date, you should use a long. This is how the system sees it and how all calculations are performed. Yes, as some point out you will eventually need to create a String so a human can read it, but where people run into trouble is when they start thinking of a date in terms of format. Format is for readability, not for calculations. java.util.Date and java.util.Calendar are fraught with issues (Effective Java, Bloch, et. al. has plenty to say about it) but are still the norm if you need handy date operations.
I have 2 different computers, each with different TimeZone.
In one computer im printing System.currentTimeMillis(), and then prints the following command in both computers:
System.out.println(new Date(123456)); --> 123456 stands for the number came in the currentTimeMillis in computer #1.
The second print (though typed hardcoded) result in different prints, in both computers.
why is that?
How about some pedantic detail.
java.util.Date is timezone-independent. Says so right in the javadoc.
You want something with respect to a particular timezone? That's java.util.Calendar.
The tricky part? When you print this stuff (with java.text.DateFormat or a subclass), that involves a Calendar (which involves a timezone). See DateFormat.setTimeZone().
It sure looks (haven't checked the implementation) like java.util.Date.toString() goes through a DateFormat. So even our (mostly) timezone-independent class gets messed up w/ timezones.
Want to get that timezone stuff out of our pure zoneless Date objects? There's Date.toGMTString(). Or you can create your own SimpleDateFormatter and use setTimeZone() to control which zone is used yourself.
why is that?
Because something like "Oct 4th 2009, 14:20" is meaningless without knowing the timezone it refers to - which you can most likely see right now, because that's my time as I write this, and it probably differs by several hours from your time even though it's the same moment in time.
Computer timestamps are usually measured in UTC (basically the timezone of Greenwich, England), and the time zone has to be taken into account when formatting them into something human readable.
Because that milliseconds number is the number of milliseconds past 1/1/1970 UTC. If you then translate to a different timezone, the rendered time will be different.
e.g. 123456 may correspond to midday at Greenwich (UTC). But that will be a different time in New York.
To confirm this, use SimpleDateFormat with a time zone output, and/or change the timezone on the second computer to match the first.
javadoc explains this well,
System.currentTimeMillis()
Note that while the unit of time of the return value is a millisecond, the granularity of the value depends on the underlying operating system and may be larger. For example, many operating systems measure time in units of tens of milliseconds.
See https://docs.oracle.com/javase/7/docs/api/java/util/Date.html#toString().
Yes, it's using timezones. It should also print them out (the three characters before the year).
I need help. I have been trying to figure out why java util date is 5 hours behind after converting from C# ticks.
in C#, the date is 6/8/2013 11:02:07 AM, I convert this date into ticks then pass it to java as long.
code snippet:
taken:
- long TICKS_AT_EPOCH = 621355968000000000L;
- long TICKS_PER_MILLISECOND = 10000;
java.util.Date date = new java.util.Date((ctime - TICKS_AT_EPOCH) / TICKS_PER_MILLISECOND);
Now java util date is Sat Jun 08 06:02:07 CDT 2013
Notice that the hour is 5 hours difference.
Any suggestions why?
You are constructing a java.util.Date based on milliseconds since 1/1/1970 UTC. You appear to be correcting from the fact that .net's System.DateTime.Ticks are based on 1/1/0001 and are 10,000 ticks to a millisecond. That is correct, but you have forgotten to adjust to UTC.
In .Net, the value coming from DateTime.Ticks is highly dependent on the DateTime.Kind property. There are three possible kinds of DateTime values.
DateTimeKind.Utc - This kind means that the value represents UTC time. It usually comes from a call to DateTime.UtcNow, but can also be constructed directly, and often is. For example, you might be retrieving UTC times from a database. You can feed the ticks from here directly into your conversion, and it will work.
DateTimeKind.Local - This usually comes from a call to DateTime.Now. The values are representative of the local time zone. You will need to convert to UTC before checking the ticks. You can do the following:
DateTime dt = DateTime.Now;
int utcTicks = dt.ToUniversalTime().Ticks;
Be aware that if the time happens during a daylight saving "fall-back" style transition, the result might be incorrect. The DateTime class has no idea about time zones. It just reflects the current local clock. If the value in dt is ambiguous, ToUniversalTime() will assume that the value is representative of standard time, even if you just retrieved it while in daylight time. This is just one of the many confusing and probablematic aspects of DateTime in .net.
DateTimeKind.Unspecified - This is the most common kind of DateTime you will encounter, and usually comes from DateTime.Parse() or a constructor like new DateTime(...). Unfortunately, there is nothing in here that will tell you about the time zone these dates are representative of. You can still try calling .ToUniversalTime(), but the framework will make the assumption that these times are representative of your local time zone, as if the kind was Local. That assumption could be completely wrong, depending on how you sourced the data. There really is no safe way to transform an Unspecified DateTime to a UTC value (ticks or otherwise).
There are some solutions, such as using DateTimeOffset instead of DateTime, or using the Noda Time library instead of the built-in types. You can read more about these problems here and here.
The time is not 5 hours behind, it's exactly the same time. The problem is with the way you print it.
You need to tell C# and Java to use the same time-zone when converting the date to string. One of them is using UTC and the other CDT.
java.util.date automatically corrects for your time zone. See this question: How to set time zone of a java.util.Date?
The ctime is UTC (Universal Coordinated Time), which is a time standard referenced to Greenwich. You're expressing your time in Central time. There's your difference.
The documentation for Date.getTimezoneOffset says:
Deprecated. As of JDK version 1.1, replaced by
-(Calendar.get(Calendar.ZONE_OFFSET) + Calendar.get(Calendar.DST_OFFSET)) / (60 * 1000).
Why was it deprecated? Is there a shorter way (Apache Commons?) to get the offset from UTC in hours/minutes? I have a Date object ... should I convert it to JodaDate for this?
And before you ask why I want the UTC offset - it's just to log it, nothing more.
There are 2 questions here.
Why was Date.getTimezoneOffset deprecated?
I think it is because they actually deprecated nearly all methods of Date and moved their logic to calendar. We are expected to use generic set and get with the parameter that says which specific field we need. This approach has some advantages: less number of methods and the ability to run setters in a loop passing a different field each time. I personally used this technique a lot: it makes code shorter and easier to maintain.
Shortcut? But what's wrong with call
Calendar.get(Calendar.DST_OFFSET) comparing to
Calendar.getTimeZoneOffset()
As far as I can see the difference is 6 characters.
Joda is a very strong library and if you really have to write a lot of sophisticated date manipulation code switch to it. I personally use the standard java.util.Calendar and don't see any reason to use external libraries: good old calendar is good enough for me.
All of the date manipulation logic was moved out of Date once the Java implementers realized that it might need to be implemented differently for different types of calendars (hence the need to use a GregorianCalendar to retrieve this info now). A Date is now just a wrapper around a UTC time value.
Take care before you paste code from this page.
Perhaps just me but I believe that in order to get the tz offset in minutes you need to do
int tzOffsetMin = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET))/(1000*60);
rather than what the Javadoc says, which is:
int tzOffsetMin = -(cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET))/(1000*60);
Calendar.ZONE_OFFSET gives you the standard offset (in msecs) from UTC. This doesn't change with DST. For example for US East Coast timezone this field will always be -6 hours regardless of DST.
Calendar.DST_OFFSET gives you the current DST offset (in msecs) - if any. For example during summer in a country that uses DST this field is likely to have the value +1 hour (1000*60*60 msecs).