Is there any way to remove the timezone component from a Java Date object that is being returned from a web service?
For example I have a start Date of 12AM. I want that to be used as 12AM local time of the clients.
I think that if the soap message doesn't have a timezone component then the local timezone is used. There are 2 other options that I have weighed which would be either doing arithmetic on the date on the client side (which I really really do not want to do) or creating a new date class that holds the day, month and year as integers(I don't need the time information). The latter option would require substantial refactoring so if there is a way to just chop off the timezone info in the soap message that would be preferable.
The client is written in .NET so if there is a way to change the how the date is interpreted on the client side that would achieve the same goal i think.
I believe I have found a solution to my problem. I used #XmlJavaTypeAdapter to change the way the date class is marshaled to Xml.
Here is the DateAdapter I used.
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class DateAdapter extends XmlAdapter<String, Date> {
// the desired format
private String pattern = "yyyy-MM-dd";
public String marshal(Date date) throws Exception {
return new SimpleDateFormat(pattern).format(date);
}
public Date unmarshal(String dateString) throws Exception {
return new SimpleDateFormat(pattern).parse(dateString);
}
}
And I used the following annotation on all of my getters that I wanted to use the "yyyy-MM-dd" date format.
#XmlJavaTypeAdapter(value=DateAdapter.class, type=Date.class)
Java Date objects don't have time zone components. They have no concept of time zones at all: they're always just milliseconds since midnight January 1st 1970, UTC.
I don't know much about the SOAP representation of dates and times... if you can persuade it that a date is all you need (rather than a date and time) you may well be fine. Otherwise, I suggest you do everything in UTC but consider it to be the local time on the client. If you're only dealing with dates, this shouldn't be too bad - although you do need to consider that midnight doesn't always occur on every date in every time zone, or it may occur twice...
Basically it's a pity that neither .NET nor Java has a decent built-in date and time API. On Java there's Joda Time where you'd want to use LocalDate by the sounds of it, to represent exactly what you're interested in (a date in whatever the local time zone is). On .NET there will (eventually) be Noda Time but that isn't ready yet. Even if both of these existed in the respective base platforms, you'd still need to persuade SOAP to serialize them appropriately :(
Related
I request a Date in a Controller with
#GetMapping(path = "/{terminal}/{date}",consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public ServiceResponse appointmentsListDate(#PathVariable Long terminal, #PathVariable #DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date date) {
Then I need to compare that Date with a stored date in database (type = timestamp without time zone).
I´m using the methods before() and after() but it fails when comparing the time part (the date comparison is good, but it doesn´t compare the time).
public Collection<EntrySlot> getAppointment( Date date) {
Collection<EntrySlot> entrySlotList=new ArrayList<>();
for(int i=0; i<appointmentList.size();i++){
Appointment appointment = ((List<Appointment>)appointmentList).get(i);
EntrySlot entrySlot = appointment.getIdEntrySlot();
if (date.before(entrySlot.getStartDate())){
entrySlotList.add(entrySlot);
}
return entrySlotList
}
At example of the entrySlot.getStartDate stored in db is 2021-05-01 16:00:00. My date is 2021-05-01 17:00:00 and when using the date.before(entrySlot.getStartDate) the result is true.
I don´t know if the problem is related to the date formatting.
Thanks in advance!
PD: I have solved the problem. The hour stored in the database has GMT+2 hours. I had to substract those hour and now I can calculate the difference even using the deprecated date.util.
java.util.Date is a lie; it does not represent dates. It presents moments in time.
'timestamp without timezone' is something completely different. You're asking the system: Hey, I have this apple. Is it better than this pear?
It'd have been better all around if the code had failed to compile but for complicated reasons, it does compile. Nevertheless, it is gobbledygook.
First, compare all the times you have into the data type that properly represents the concept of 'timestamp without timezone', which is java.time.LocalDateTime.
Most DB engines can give you this directly; at the JDBC level, call .getObject(idxOrColName, LocalDateTime.class). A few rusty old JDBC drivers can't do this, in which case you're forced to call e.g. .getTimestamp, which will convert a timestamp-without-timezone in-flight to a moment-in-time-devoid-of-context, and you then have to unconvert this messed up conversion, preferably ASAP.
Once you have that, put your target in terms of LocalDateTime as well, and now compare the two. If it fails now, you can just debug each process individually, because then one of the two processes that end in you having an instance of LDT, is broken and it is instantly obvious which one: It's the one where printing that LDT does not show what you expected.
NB: All date/time related classes in java.util, java.sql, and the (Gregorian)Calendar class are obsolete and bad API which lead to exactly the problems you have now. Don't use those, or if you're forced into it, convert them to a java.time type immediately and debug this conversion on its own before continuing with the program.
I have a javax.ws.rs REST API that accepts an object body that has a timestamp field mapped to a util Date with JPA, but something sending to it is sending a timestamp with extra milliseconds (maybe supposed to be nanoseconds?) and that causes the date to be in the future when I use the object within my request handler method.
for example this came in: "TimeStamp": "2020-04-24T16:26:11.9376071Z",
and it resolved to "2020-04-24T19:02:27" in the object.
If I use Postman and send the exact same message just with the TimeStamp reduced to 2 milliseconds it works as expected and the date is correct.
So, assuming I can't change what's being sent but want to be able to handle it, how can I shorten the milliseconds so the Date resolves correctly?
Such strings are parsed according to a pattern. The numbers following the 'dot' are parsed as milliseconds, and parsing dates is evidently configured in lenient mode, which means overflow is adjusted into the higher fields. If you parse 9376071 as milliseconds, that's 9376.071 seconds; that's about 2 hours and change. Add that to '16:26:11' and you get 19:02. So, that's what's going wrong here.
I don't see enough detail in the mechanism you're using to transit this string into a value of type java.util.Date - in various frameworks you can explicitly specify the pattern. However, the 'old' API (the one java.util.Date belongs to cannot parse this input - it has no option to parse that dangling batch of digits properly. Yes, really. The old API (java.text.SimpleDateFormat) cannot actually read ISO8601 - a grievous ommision which strongly suggests you really, really need to stop using this incapable old deprecated stuff. (ISO8601 does indeed allow any number of digits on the fractional part, and it allows a fractional part on the 'lowest' entry in the input, therefore, the timestamp you get, while somewhat exotic, fits the ISO8601 spec).
But, good news!
The newer API does it just fine!
import java.time.Instant;
import java.time.format.DateTimeFormatter;
class Test { public static void main(String[] args) {
Instant parsed =
DateTimeFormatter.ISO_INSTANT.parse("2020-04-24T16:26:11.9376071Z", Instant::from);
System.out.println(parsed);
}}
I'm not entirely sure how you can tell your framework to stop using the bad API, but once you've managed to tell it to stop hitting itself in the face with the old one, all will be well again.
Sidenote: j.u.Date is a really bad type to use; it does not represent a date at all, but an instant in time, and badly at that. In general I wouldn't use API that is so epically badly named! May I suggest java.time.Instant instead? Its name matches what it represents, and should be drop-in ready. Another workable option is ZonedDateTime or LocalDateTime depending on what it represents).
I want to create an instance of Calendar with string date coming from server. Now I don't know what format server is sending .
It can be changed for different countries. I know I can ask them to add another key for dateFormat and create Calendar from it. But still I want to know Is there any way to create Calendar Instance without knowing current string date format.
I have gone through this and this. But none fulfill my requirement
This is impossible.
If the server sends the value "1/2/2017", you have no way of knowing if this refers to January 2nd or February 1st.
If the server sends the value "מָחָר", in theory you could realize that this might be a Hebrew translation of the word "tomorrow" (at least, according to Google Translate), but even then, it is not clear whether this is to be taken relative to today or some other date.
If the server sends the value "I want to create an instance of Calendar with string date coming from server", you have no means of creating a date from that, at least using any algorithm that would make sense to people.
And so on.
The only reason a server should return a date in an arbitrary format is if the date would only ever be read by the user who provided the value in the first place and presented as plain text verbatim, without parsing. Otherwise, the server should supply the date in a standardized format, with the UI consuming that date being responsible for formatting it in a user-friendly (and, ideally, locale-aware) fashion.
You're welcome to try to brute-force the problem, iterating over a series of date formats and seeing if any result in a seemingly-valid date. This fails the 1/2/2017 scenario (as there are at least two formats that would return a seemingly-valid date), but perhaps you know enough about the server to narrow down the possible formats to reduce the odds of collisions like this.
The Joda Date & Time API has a date parser which can parse date strings in many formats. Note that some datetime strings can be ambiguous: 10-09-2003 could mean October 9 or September 10.
So me and my partner have been working on this project for a while now. We work with dates A LOT in this project, and we recently noticed an issue, and we are rather deep in at this point.
We store our times in SQLlite (Android project) as a formatted string, since a lot of the time they are directly bound to listviews and such.
The problem we noticed, which i found kind of odd, is that that SimpleDateTimeFormat object, when used to format to 24h time (its a medical based project, so 24h time is the convention here) 12:00am-12:59am are formatted to 24:00-24:59, instead of 00:00-00:59...
This isn't too much of an issue until we query the database and order the results by the dates, any data that is between 12:00am and 12:59am will show up at the end of the list, but it should show up at the beginning...
Anyone else encountered this problem? or know a way around it? The best thing possible would be a way to store the data as 00:00 not 24:00.
Cheers
I strongly suspect you're using the wrong pattern. We've got to guess as you haven't posted any code (hint, hint), but I suspect you're using a pattern such as
kk:mm:ss
instead of
HH:mm:ss
Sample code:
import java.util.*;
import java.text.*;
public class Test {
public static void main(String[] args) throws Exception {
SimpleDateFormat broken = new SimpleDateFormat("kk:mm:ss");
broken.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
SimpleDateFormat working = new SimpleDateFormat("HH:mm:ss");
working.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
Date epoch = new Date(0);
System.out.println(broken.format(epoch));
System.out.println(working.format(epoch));
}
}
Additionally, as others have pointed out, you shouldn't be storing your values in string format to start with... avoid string conversions wherever you can, as each conversion is a potential pain point.
Please read this and this about how SQLite stores dates (or doesn't store dates). SQLite doesn't have a "Date" type, so it is stored as a string. You should store your date as an integer (milliseconds), and then you can use date and time functions to pull them out (from the first link).
From the documentation
1.2 Date and Time Datatype
SQLite does not have a storage class set aside for storing dates
and/or times. Instead, the built-in Date And Time Functions of SQLite
are capable of storing dates and times as TEXT, REAL, or INTEGER
values:
TEXT as ISO8601 strings ("YYYY-MM-DD HH:MM:SS.SSS"). REAL as Julian
day numbers, the number of days since noon in Greenwich on November
24, 4714 B.C. according to the proleptic Gregorian calendar. INTEGER
as Unix Time, the number of seconds since 1970-01-01 00:00:00 UTC.
Applications can chose to store dates and times in any of these
formats and freely convert between formats using the built-in date and
time functions.
I prefer INTEGER / Unix time storage, then use the built in date and time functions to format when pulling from DB.
EDIT: Also, this will take care of sorting. I'm guessing your current "sorting" of the dates in SQLite is string based, which is bad mmmmkay.
What is the format string you are passing to your SimpleDateFormat? According to the docs, using 'H' for the hours should get you 0-23, using 'k' should get you 1-24.
I have to use java.util.Calendar in GWT entry point, but I got error while running the application, that is because GWT is not able to find source code, is there anyway I could fix this issue.
Thanks in advance!!!
java.util.Calendar is not an emulated class. You can find a list of emulated classes here:
http://code.google.com/webtoolkit/doc/latest/RefJreEmulation.html
I would strongly advise not to use any date/calendar library on the client side. You will probably only get yourself into trouble. In fact, even though java.sql.Date and java.util.Date are emulated in GWT, I would not use these either. If you're looking to use Calendar, then chances are you want to support timezones on the client. Using the emulated Date classes, you will somehow have to convert the client's Date from the browser's timezone to some target timezone (GMT or whatever the user defined in user preferences?). This will most definitely be error prone. Using GWT's TimeZone adds other issues. For instance, how do you map between java TimeZones and GWT TimeZones?
I recommend doing all date manipulation AND formatting on the server. On the client, you can simply use a date/month/year triplet. The server can have an association between user (or organization) and java.util.TimeZone (or joda timezone). Using the triplet and timezone you can easily create the specific instance in time.
You may be able to use com.google.gwt.user.datepicker.client.CalendarUtil.
No there is no way to use the java.util.Calendar in GWT because there is no equivalent in JavaScript. But there is an accepted feature request for it. Maybe you will find some hints in the comments of the request.
The following shows how to use Joda Time to extract any date information from a Java Date type with Joda Times format() function and use it to build a new Date() using Joda Time's parse() function.
static DateTimeFormat dtf = DateTimeFormat.getFormat("yyyy-MM-dd HH:mm:ss.SSS");
static DateTimeFormat datefmt = DateTimeFormat.getFormat("yyyy-MM-dd ");
static DateTimeFormat timefmt = DateTimeFormat.getFormat("HH:mm:ss.SSS");
public Date getDateTime(Date date, Date time) {
String datetime = datefmt.format(date) + timefmt.format(time);
return dtf.parse(datetime);
}
Have you tried adding actual code of the class to your project? Some Java SDK classes compile well even though they are not in JRE white list.
For those who prefer implementing the math directly, here is a solution for how to add days to an existing date object without using Calendar or any deprecated functions:
private Date addDays(Date dateIn, int numDays)
{
long milisPerDay = 86400000;
// convert the dateIn to milliseconds
long dateInMilis = dateIn.getTime();
// add numDays to the date
dateInMilis = dateInMilis + (numDays * milisPerDay);
return new Date(dateInMilis);
}
Here's how to get the current year as a String (very useful for Copyright notices)
long time = System.currentTimeMillis();
long milisPerYear = new BigInteger("31536000000").longValue();
String currentYear = String.valueOf((int) Math.floor(time / milisPerYear) + 1970);
Finding the constants such as number of miliseconds in a day, year, etc. is easy with Google. The tricky part is adding months, since the number of milliseconds in a month is going to depend on the month. If there's any demand for it, I'd be happy to write a function and post it here in order to add and subtract months.