I have a Joda Date Time object that contains date and time fields and I wish to extract the date and time portions into 2 different sql date and time objects (java.sql.). I thought converting the DateTime to milliseconds and storing it in the respective sql objects would do the trick however it produces calculation errors further upstream in my app logic as one is === to the other.
Best way I've found to do this so far is what I've described in my comment on the question and then convert back to sql time using:
new java.sql.Date(locDate.toDateTime(LocalTime.MIDNIGHT).getMillis()));
new java.sql.Time(locTime.toDateTimeToday().getMillis()) );
Couldn't find anything in the DateTime object API to extract the respective parts.
Related
My project uses Javascript and Java (Android) for the client and Java for the backend.
When I started working on my project, I stored dates as days from epoch (long) and all was good. I then found out that my project doesn't work well with timezones. Suddenly dates were +1 -1 days off. Depending on the client's location in the world.
After a short investigation, I saw that the foolproof way to avoid it was to store the dates as String yyyy-MM-ddT00:00 so when using the Javascript's new Date(dateStr), it creates it correctly and all was good. Ofcourse I could store the dates as yyyy-MM-dd and just send it to the client as yyyy-MM-ddT00:00 but that won't solve the question I have.
After that, I was wondering whether Java (backend) is handled correctly. I use LocalDate when I want to "play" with dates and LocalDate.parse doesn't like yyyy-MM-ddT00:00 format, instead it works with yyyy-MM-dd so whenever I needed dates, I did LocalDate.parse(dateStr.substring(0,10)). LocalDateTime does work with yyyy-MM-ddT00:00 but I don't need the time part and it had its own issues, which I don't remember what they were at the moment.
So now I have a lot of String manipulation (inside loops) that actually creates more String objects. One can say it's not that much of a stress and I shouldn't pay attention to that but I want to make sure I'm not missing something and maybe there's another way (maybe silly enough that I've missed) to overcome this.
Thanks
Update: The events are stored from a different source and only the date itself is important so if an event happened on 2020-06-17, this is the date all users should see, no matter where they are.
I'm using new Date(dateStr) in Javascript. If dateStr is 2020-06-17, the date object uses the client's timezone and the date might be +-1 depending on the client's timezone. If dateStr is 2020-06-17T00:00 then the date object is created as expected no matter where the client is located.
Assuming the above, which I hope is clearer now, creating String objects over and over again is a memory stress that I should consider or is it something Java handles with no problem and I shouldn't worry about this?
My question was closed and I was told to edit it to be more focused. After editing my question, how can I re-open my question to answers?
As you have discovered, storing dates in terms of days since some epoch only works if everyone who uses your system is using the same time zone. If two different users in different time zones have a different idea about the date on which some event occurred (e.g., the person in New York says that the system crashed on Sunday night, but the the person in Hong Kong says it crashed on Monday morning), then you have to store the time zone in which the event occurred in order to show the date of that event accurately.
But if that's the situation you're in, why not just store the time zone along with the date? There's no compelling reason to combine the date and timezone into a string.
When you parse a ISO-formatted timestamp into a LocalDate using only the first 10 characters, be aware that you're losing the time zone information. Implicitly the LocalDate that you get is in the time zone of the original timestamp. So if the original timestamp is New York time, and you take the date part and add 1 day, then you'll get the next day in the New York time zone. But if you then take the date from a second timestamp, you can't compare it to the date you got from the first timestamp, in terms of determining if it represents the "same day." You can only test for "same day" if both dates are implicitly in the same time zone.
UPDATE
After reading your additional comments, I realize that what's happening is this. You have a date stored in your database, like 2020-06-15. You send that to the UI as the string '2020-06-15' and then do new Date('2020-06-15') and then you're surprised when you render the date in the UI and get June 14!
This is the transformation that happens:
The string '2016-06-15' gets parsed into a JavaScript Date representing midnight UTC on the June 15.
When you render the date, it gets converted into a string using the browser's local time zone, which (if you're in the United States) will give you June 14, because at midnight UTC on June 15 it's still June 14 in all time zones west of Greenwich.
You discovered that if you make the string "2020-06-15T00:00" that it works, because now JavaScript uses the browser's local time zone to parse the string. In other words, this string means midnight local time, not UTC, on June 15. So now the sequence is:
'2020-06-15T00:00' gets parsed using the local time zone and becomes June 15 4:00AM UTC.
When you render the date, it gets converted back to local time and is rendered as June 15.
The easiest way to avoid all this messiness is just to send the regular date string '2020-06-15' to the UI and render it using DateTimeFormat, specifying the time zone as UTC:
new Intl.DateTimeFormat('en-US', {timeZone: 'UTC'}).format(d)
Since dates in JavaScript are always UTC, and you're asking DateTimeFormat to output the date in UTC, no date shift occurs.
You could also use the Date methods getUTCFullYear, getUTCMonth, etc. to get the date components and format them however you like.
Once you're no longer sending dates back and forth with "T00:00" appended, you can just use LocalDate on the Java side.
Don't spend even a second worrying about the time required to manipulate strings. Think about the incredible amount of string manipulation that is necessary to build even a simple web page. A few more strings here and there isn't going to make a difference.
I have been reading different articles on the said question yet i am unable to figure out what should be the best strategy to store the date in db.
I will be receiving the ISO8601 date via path-param in a rest call. What I have decided
Use Joda-Time to parse the date.
Extract UTC-0 time out of the date and the hours offset
Store UTC-0 in DateTime datatype in mysql db and store offset in varchar(5).
When I have to search something based on the date (an exposed rest api). I will use the search criteria (input date) extract the UTC-0 time and hours offset and compare the two columns in the db i.e. where table.dateInUTC0 = :inputDateInUTC0 AND table.hoursOffset = :inputHoursOffset
I am not sure about step 4. Am i doing i right ?
I am not sure about step 4. Am i doing i right ?
Really, it depends on what you are trying to do.
If you want the search to only match if the searcher is using the same timezone as the original data, then you are doing it right.
If you don't want that, you are doing it wrong.
Ask yourself this: If you enter the same date / time in your local time zone and UTC (or some other time zone), do they mean the same thing for clients of your server? Should they?
I'm using a HSQLDB to make a small program (with JavaFX gui) and I'm currently trying to get the "reservation" part to work (the user can add new ones or search for existing ones in a restricted period of time).
For that I already added a few dates beforehand (I'm using a database.sql script), e.g.:
INSERT INTO reservations(begin, end) VALUES ('2013-08-01', '2013-08-31')
I already wrote a few methods (create, update, delete, search, findAll) and now I'm kind of stuck on the "create" part.
I want to insert new reservations into the DB with
pstmt = con.prepareStatement("INSERT INTO reservations(begin, end) VALUES (?,?)");
but I'm having problems creating new Dates that I can insert.
pstmt.setDate(1, (java.sql.Date) beg);
Doesn't work (I'm using java.util.Date objects to save the exported dates from the DB), it just aborts my tests (jUnit).
Calendar cal1 = Calendar.getInstance();
cal1.set(2014, 0, 1);
Date beginn = cal1.getTime();
only creates dates in the form of: Wed Jan 01 12:23:15 CET 2014
But (and I don't know how exactly dates are saved in HSQLDB) I want the date to be "YYYY-MM-DD".
So, what's the best way of converting the calendar dates into the format I need (and caste them? Unfortunately, casting a String to Date doesn't work). And: Is my approach of using java.util.Date dates okay if I'm going to use JavaFX to let the user select a starting and an end date?
Instead of (java.sql.Date) beg causing a ClassCastException you should write:
new java.sql.Date(beg.getTime()); // provided beg is of type java.util.Date as you wrote
If you use strings in VALUES-clause you might consider JDBC-escape-syntax for dates. And your statement "only creates dates in the form of: Wed Jan 01 12:23:15 CET 2014" does not matter at all because you only see the output of method toString()of java.util.Date. It is not relevant for the internal state or storage in db. Your wish "I want the date to be "YYYY-MM-DD"." is rather relevant for representation layer of your application, not for the internal storage format of db which you have no control about other than choosing the appropriate db column type (here: ANSI-SQL-DATE).
In the representation layer you can use classes like SimpleDateFormatwith pattern "yyyy-MM-dd" for the output you wish.
EDIT (because of questions in comments):
Okay, you really don't need to worry about the toString()-representation of a java.util.Date-timestamp. Its internal state is only a long representing the elapsed millis since 1970-01-01 not counting leap seconds. Just ignore the standard output of java.util.Date which rather displays the system zone context but not so much the internal state. Using a.before(b) is quite okay and has nothing to do with the weird output of toString()-method of java.util.Date.
Furthermore: You have no real control about how your database tool displays the date column values. That is the secret of the tool you use. The internal state inside db might be quite different so every db is like a kind of black box.
But when you read the date values from db and present the data to the user then and exactly then you have to worry about the representation of the java.util.Date-objects. For this purpose I have recommended to use SimpleDateFormat - see above. But this adaptation (conversion to readable human date format) is not in db-tool, not in the JDBC-layer, but only in user-representation layer, normally in UI.
This question has few sub-questions!
What is best data type for storing date?
java-s Date, or just long - in miliseconds, formated String?
Client/Server time-zone problem
a) How to show date on client side (correct time zone)
b) If client inserts date, server needs to insert date in servers timezone or better fixed app timezone? (correct api?)
Sorting is easy with long data type, but is it working with Date?
Manipulating (for example select records for last 4 days, or between two dates, etc...).
Is there any good manual for this topic!
Currently, I am using long for date data type, but it somehow does't feel right (for example browsing in admin console is confusing).
Thanks!
java.util.Date is a supported type
How you show this to the user is a more generic java problem. All dates are stored in UTC. I suggest you take a look at joda-time for handling timezones and dates.
Yes, sorting of Date objects is supported in queries etc.
Filtering is also supported, eg, date > yesterday && date < today. Don't forget to bear in mind there are limitations when you impose filters. For example, those inequality filters can only apply to one property at a time. See restrictions on queries
Which is the most beneficial in Java and a DB for DateTime? (Using JodaTime as Date)
(DateTime object (Java) + TIMESTAMP (DB) ) VS (Milliseconds long (Java) + BIGINT(DB)
for the use of DateTime information in Java Web application backed by an underlying Database
Areas of interest
manipulating, processing and memory usage in Java
saving using efficient storage space in
a MySQL database
ease of porting a BIGINT/TIMESTAMP column to other DBs
ease of searching the DB for a BIGINT/TIMESTAMP or between two BIGINTs/TIMESTAMPs
E.g. Say I had an event with a start & end DateTime.
Is it faster to search for events on dates using BIGINT in the DB than TIMESTAMPS
I might be swapping the underlying DB as scalability and retrieval issues arise.
Would saving the DateTime as a TIMESTAMP in a MySQL DB lead problems when porting to another DB like Oracle?
I currently use the Joda DateTime in java then storing the millisecond of that value.
When retrieving it, I convert the milliseconds back to a DateTime object and display it.
I’m always using the “milliseconds since 1970” approach. This way I don’t have to worry about which timezone the date belongs to because the date in the database is always UTC.
There are really two questions here. First, what abstraction should you use in Java to represent time? Joda Time is definitely better than java.util.Date. If you are wondering whether to simply use a long -- I imagine you can't get away with that if you need to do any date manipulation or comparison. So, Joda Time.
And then it is definitely best to use TIMESTAMP for this in MySQL as it will be nearly identical storage-wise and MySQL will treat the value appropriately, as a date, when you want to use date functions on the column. JDBC drivers will also understand that it should be mapped to a date type.
I can't imagine you will have trouble porting a date type, represented correctly as a date in your schema, to another database, should you need to. I can imagine problems if you treat the date type as a bigint, which is less correct.
So, simply choose the most correct types here. I doubt there is any performance win available from choosing a less suitable type anyway.
Of course it depends on what you want to do with the data, but I would recommend using the DB's native type for time/date (whatever that may be) for storage in the DB. That is the standard for databases, and most date/time functions in DBs expect data in that form.
Special note about MySQL:
While you can use TIMESTAMP for date/time values, be aware that TIMESTAMP cannot record dates earlier than 1970-01-01. So while it's ok for dates close to "now" (such as creation/modification dates), it is not appropriat for possibly historical dates such as date of birth. So only use TIMESTAMP if you are completely certain you will never need historical dates.