How can we dynamically change the timezone in java rest api response? - java

We have api: call_summary/
{
"id": 2,
"number: "xyz",
"call_time": "2021-10-11T03:50:23Z"
}
We have multiple users with various timezones like ADT, EDT, IST, etc. When users access this API the call_time should change according to user timezone. I tried to use #JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "IST"), but this won't allow us to change the call_time dynamically.
Is there any way to do it using annotations or filters?

I would recommend storing call_time in two columns, UTC and users local time-zone.
By doing so, it will eliminate complexity and confusion at both ends (server and client)

Check the following link, it may help you: Pass browser timezone to the backend springboot application to generate reports with dates as per the browser timezone. According to the latter, you can use TimeZone as input to your controller. You could do something like the following:
#RestController
public class TestController {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
#GetMapping(value = "/test")
public String generate(TimeZone timezone) throws IOException {
return LocalDateTime.now().atZone(timezone.toZoneId()).format(formatter);
}
}
Alternatively, you could get the timezone from HttpServletRequest.

JSON Serialize is the best fit for this custom data conversion as per user or user role. I created the converter class and called by #JsonSerialize(converter = LocalDateTimeToStringConverter.class) and #JsonDeserialize(converter = StringToLocalDatetimeConverter.class). It worked as per my expection.
For reference, I attached the sample link below.
Custom conversion using JSON-Serialize-Deserialize

Related

Always save date to today's date in database using jhipster

I have created one entity in jhipster using jhipster-jdl.jh file which is as shown below:
entity EmployeeLeave{
appliedDate LocalDate required,
fromDate LocalDate required,
toDate LocalDate required,
status String
}
From these fields i want appliedDate as today's date in database(MySql).
I have tried this from Angular side in jhipster code but none helps well.
Is there any way so that when creating a record for employeeLeave there should be always appliedDate equals to today's date.
Preferably i want solution from Angular side. Other solutions are also welcomed.
Technologies:
Database: Mysql,
Spring-boot,
Angular 4,
Jhipster.
You can initialize your date inside your class :
public class EmployeeLeave{
LocaleDate yourDate = LocaleDate.now();
//other fields
}
So, appliedDate will always be today's date. I am using Java 8 but the idea is here.
LocaleDate.now() is server time. If server is in another time zone than user, may insert incorrect date.
Isn't better to define date in .controller.js like:
var now = new Date();
vm.employeeLeave.appliedDate=now;
vm.isSaving = true;
EmployeeLeave.update(vm.employeeLeave, onSaveSuccess, onSaveError);
?

JSON date changed

I have a web application where user can post the message to a restful API, so that that information can be saved in the database.
My problem when the data is sent from the UI, the date sent is "effStartDate":"2016-08-13" , but when i see the date value in the java code it is showing Fri Aug 12 20:00:00 EDT 2016.
I am using AngularJS,Spring and iBatis as the ORM tool. Attached are the screen shots with data sent from UI and what i see in the backend code.
can anyone help me with this?
You can add annotations to realize in the entity.
(Have to rely on JackJson`s jar)
and Then add in required fields
"#JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")"
You can treat the date as a string. Something like this
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
You can try this use date format from javascript code to send requests to a server by REST api.
For example:
effStartDate.toISOString();
The toISOString() method returns a string in simplified extended ISO format

Spring + Thymeleaf: time in user's timezone

How can I print date and time is specified timezone with Thymeleaf? Something like:
<span th:text="${#dates.format(myDate, 'yyyy-MM-dd HH:mm', 'PST')}">2010-01-01 16:30</span>
Another approach to the same problem may be to use your own static methods:
${T(xx.xxx.utils.DateUtils).format(myDate, 'yyyy-MM-dd HH:mm', 'CET')}
public static String format(Date date, String pattern, String timeZone) {
TimeZone tz = TimeZone.getTimeZone(timeZone);
return DateFormatUtils.format(date, pattern, tz);
}
or even directly from lang3 (does not work on GAE because of some class access restrictions in sun.util.calendar package):
<div th:with="timeZone=${T(java.util.TimeZone).getTimeZone('CET')}">
<span th:text="${T(org.apache.commons.lang3.time.DateFormatUtils).format(myDate, 'yyyy-MM-dd HH:mm', timeZone)}"></span>
</div>
As I was puzzled by this question, I searched extensively for possible solutions.
These are my findings:
I did not found any clean function for changing timezone and displaying it like it is in jsp:
<fmt:timeZone value="US">
<fmt:formatDate value="${today}" type="both" />
</fmt:timeZone>
Possible solution, that works would be to create calendar instance using createForTimeZone and format it, since it returns a raw calendar value, so from this:
#calendars.createForTimeZone(year, month, day, hour, minute, second, milisecond, Object timezone)
you would get something like this:
java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="PST",offset=-28800000,dstSavings=3600000,useDaylight=true,transitions=185,lastRule=java.util.SimpleTimeZone[id=PST,offset=-28800000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2014,MONTH=1,WEEK_OF_YEAR=14,WEEK_OF_MONTH=1,DAY_OF_MONTH=24,DAY_OF_YEAR=91,DAY_OF_WEEK=3,DAY_OF_WEEK_IN_MONTH=1,AM_PM=0,HOUR=6,HOUR_OF_DAY=7,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=-28800000,DST_OFFSET=3600000]
As you can see (you have to look carefully) it did converted time to the timezone provided.
Now, I still haven't gotten to the point where I can get it all to work fine, but if you add calendars.format in front of this, you would get it to properly show time in the given timezone. ${#calendars.format(#calendars.createForTimeZone(year, month, day, hour, minute, second, milisecond, Object timezone), 'dd-MMM-yyyy HH:mm')}
Adding "zzz" to the end of the string, always return my locale timezone. I guess there are way to work this out so it looks better, but main point for me was to find out if it was possible at all.
Examples that work:
${#dates.format(#calendars.createForTimeZone(#calendars.year(ticket.ticketDate), #calendars.month(ticket.ticketDate), #calendars.day(ticket.ticketDate), #calendars.hour(ticket.ticketDate), #calendars.minute(ticket.ticketDate),'PST'), 'yyyy-MMM-dd HH:mm')}
${#calendars.format(#calendars.createForTimeZone(#calendars.year(ticket.ticketDate), #calendars.month(ticket.ticketDate), #calendars.day(ticket.ticketDate), #calendars.hour(ticket.ticketDate), #calendars.minute(ticket.ticketDate),'CET'), 'yyyy-MMM-dd HH:mm')}
and either one would return identical results.
Here are the results when comparing same format, using PST and CET:
2014-Feb-24 16:00
2014-Feb-24 07:00
or:
2014-Mar-01 03:00
2014-Feb-28 18:00
Regards,
I found this answer when I wanted to format LocalDateTime to some time zone in the templates. It turned out that the purpose of LocalDateTime is to do not work with time zones at all.
However, there is also a class called ZonedDateTime which purpose is obvious. You can also use LocalDateTime#atZone which creates a new instance of local converted to the new zone.
Note that usual DateTimeFormatter ignores any time zone settings in the case of local date time but not in the case of zoned date time. So you can use usual formatters as well in the templates.
The server renders the page based on the server time, in order to get the timezone of the user from the request, the user when submitting the request should attach the timezone information in the request headers or parameters, so that the server knows the appropriate time zone to render. To do that, use javascript to get the browser's time zone.
Using Thymeleaf's #temporals doesn't provide the ability to use the constructor new Temporals(locale, zoneId).
Create your own Temporals temporals = new Temporals(LocaleContextHolder.getLocale(), zone) (somewhere, session bean, or so - zone should probably come from your user's preferences), and put it available in the controller (eg. as "temporalsZone").
Then use it in the UI: th:text="${temporalsZone.format(value, pattern, #locale)}"> and enjoy the full support of #temporals.
If you add org.thymeleaf.extras:thymeleaf-extras-java8time as a dependency, you get the #temporals object to help format types like:
Instant
LocalDateTime
ZonedDateTime
etc
If you want to format java.util.Date you can use #dates instead.
The methods you're looking for are #dates.format or #temporals.format. You can specify a Locale as the third argument. The general syntax is #temporals.format(<temporal object>, <pattern>, <optional locale>)
Examples:
th:text="${#temporals.format(myDate, 'dd-MM-yyyy', new java.util.Locale('en'))}"
th:text="${#temporals.format(myDate, 'dd-MM-yyyy', #java.util.Locale#ENGLISH)}"
Note that this is true even if you're working with Kotlin Spring Boot. The syntax in the Thymeleaf template isn't Java, it's an OGNL Expression.
https://commons.apache.org/proper/commons-ognl/language-guide.html
I'll quote the useful syntax used here:
#variable
Context variable reference
#class#method(args)
Static method reference
#class#field
Static field reference
new class(args)
Constructor call
One other option is to specify the Locale in the Thymeleaf context, if you just want to override the default system Locale. I've included a Kotlin snippet of how that might work:
val context = Context() // org.thymeleaf.Context
context.locale = Locale.ENGLISH
context.setVariable("x", 0)
templateEngine.process("classpath:template.html", context)
Then you can simply use th:text="${#temporals.format(datum.timestamp, 'E MMM dd yyyy')} without the explicit Locale argument.

java convert xmldate to string date, probably timezone issue

I have dates in XML
<date>1980-03-07+03:00</date>
I use this data in my tests and i get it from XML, but in the web page it is displayed in dd.MM.yyyy form, so i have to convert it to that format. I have following method for this:
public String convertXMLDateToString(String xmlDate) throws ParseException, DatatypeConfigurationException {
return new SimpleDateFormat("dd.MM.yyyy").format(new Date(DatatypeConverter.parseDate(xmlDate).getTimeInMillis())) ;
}
but this is returning 06.03.1980 . It is probably a timezone issue - how to i get the right date? The reason for using strings is that these are webdriver tests that i am writing.
Its returning actually the correct date. Either your test data is corrupted or you have a bug in your application. However if you're sure, that there's no bug and test data isn't corrupted, you can set the correct time zone manually, by doing something like this:
Calendar calendar = DatatypeConverter.parseDate(xmlDate);
calendar.setTimeZone(TimeZone.getDefault());
return new SimpleDateFormat("dd.MM.yyyy").format(new Date(calendar.getTimeInMillis()));

Date Formatting Issue

The following Java test passes on our US hosted build server. It also passes on non-US servers, e.g. in Germany. It fails on my local server, which is running in Ireland. The following code illustrates a failing test.
org.junit.ComparisonFailure: expected:<[4/6/09 11:30 AM]> but was:<[06/04/09 11:30]>
Is there a system setting I can provide to get these tests passing locally?
public void testFormattedDate() {
// Set the default time zone in case this unit test is executed in a different country
TimeZone.setDefault(TimeZone.getTimeZone(DateUtil.DEFAULT_TIMEZONE));
final Date utilDate = new Date();
utilDate.setDate(6);
utilDate.setHours(11);
utilDate.setMinutes(30);
utilDate.setMonth(3);
utilDate.setSeconds(45);
utilDate.setYear(109);
SimpleDateFormat dateFormatter = new SimpleDateFormat();
final String formattedOutput = dateFormatter.format(utilDate);
Assert.assertEquals("4/6/09 11:30 AM", formattedOutput);
}
Have to tried to provide a pattern to the SimpleDateFormat ?
SimpleDateFormat dateFormatter = new SimpleDateFormat("d/M/yy HH:mm a");
The time is correct but the SimpleDateFormat() constructor internally calls a package private construtor using Locale.getDefault(). Thus you either can provide a format of your own or provide another locale, which seems to only be possible with a custom format, i.e. using SimpleDateFormat(String pattern, Locale locale).
The problem is that SimpleDateFormat() uses a locale dependent pattern, thus the system's default locale might result in a different pattern than what you get in the USA (I assume the German server doesn't use the German locale as its default since then you should get a date like 06.04.09 11:30).

Categories