Java, failed test after changing Time zone on PC - java

Initially I had quite simple test:
#Test
public void testMe() {
System.out.println("Records in H2 db:");
List<DateRangeBean> all = dateRangeServiceImpl.findAll();
all.forEach(x -> System.out.println(x.getDateTo()));
Clock.system(ZoneId.of("UTC"));
ZonedDateTime currentDate = ZonedDateTime.of(2016, 8, 9, 0, 0, 0, 0, clock.getZone());
Date currentDate_date = Date.from(currentDate.toInstant());
System.out.println("Current Date is: " + currentDate_date);
List<DateRangeBean> result = new ArrayList<>();
dateRangeServiceImpl.findGreaterDateTo(currentDate_date).iterator().forEachRemaining(result::add);
result.forEach(x -> System.out.println(x.getDateTo()));
assertEquals(result.size(), 2);
}
that always was executed on PC with default TimeZone UTC and with the following output:
Records in H2 db:
Mon Aug 08 00:00:00 UTC 2016
Thu Oct 20 00:00:00 UTC 2016
Thu Oct 20 00:00:00 UTC 2016
Current Date is: Tue Aug 09 00:00:00 UTC 2016
Thu Oct 20 00:00:00 UTC 2016
Thu Oct 20 00:00:00 UTC 2016
where:
dateRangeServiceImpl.findAll() implemented as:
public List<DateRangeBean> findAll (){
List<DateRangeBean> result = new ArrayList<>();
dateRangeRepository.findAll().iterator().forEachRemaining(result::add);
return result;
}
dateRangeServiceImpl.findGreatedDateTo(Date date):
public List<DateRangeBean> test (Date currentDate){
List<DateRangeBean> result = new ArrayList<>();
dateRangeRepository.findGreatedDateTo(currentDate).iterator().forEachRemaining(result::add);
return result;
}
and dateRangeRepository - is pure interface as part of Spring Data
public interface DateRangeRepository extends PagingAndSortingRepository<DateRangeBean, Long> {
#Query("from DateRangeBean drb where (drb.dateTo >= :currentDate)")
List<DateRangeBean> findGreatedDateTo(#Param("currentDate") Date currentDate);
}
and DateRangeBean:
#Entity
public class DateRangeBean implements java.io.Serializable {
#Temporal(TemporalType.DATE)
#Column(name = "date_To", length = 10)
private Date dateTo;
.....................
public Date getDateTo() {
return new Date(this.dateTo.getTime());
}
public void setDateTo(Date dateTo) {
this.dateTo = new Date(dateTo.getTime());
}
}
Today I have tried to run this test on PC with Time Zone: UTC -07:00 and test failed with the following output:
Records in H2 db:
Mon Aug 08 00:00:00 MST 2016
Thu Oct 20 00:00:00 MST 2016
Thu Oct 20 00:00:00 MST 2016
Current Date is: Mon Aug 08 17:00:00 MST 2016
Mon Aug 08 00:00:00 MST 2016
Thu Oct 20 00:00:00 MST 2016
Thu Oct 20 00:00:00 MST 2016
java.lang.AssertionError: expected [2] but found [3]
Expected :2
Actual :3
Okey, maybe, it is reasonable: we defined currentDate variable Aug 9 UTC TZ, but on the next step we re-converted currentDate to currentDate_date in MST TZ and as result it is Aug 8.
BUT:
Q1:
based on our #Query: drb.DateTo >= :currentDate
in current case: Mon Aug 08 00:00:00 MST 2016 >= Mon Aug 08 17:00:00 MST 2016 - this statement is incorrect!
Assume, that Spring Data compares only Day, Month, Year and trims Time segment.
Is it correct??
Q2:
I tried to fix the test putting the timezone directly in the test:
public void testMe() {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
..............
}
But I still getting failed result:
Records in H2 db:
Mon Aug 08 07:00:00 UTC 2016
Thu Oct 20 07:00:00 UTC 2016
Thu Oct 20 07:00:00 UTC 2016
Current Date is: Tue Aug 09 00:00:00 UTC 2016
Mon Aug 08 07:00:00 UTC 2016
Thu Oct 20 07:00:00 UTC 2016
Thu Oct 20 07:00:00 UTC 2016
java.lang.AssertionError: expected [2] but found [3]
And at the moment I can't understand how is it possible:
Mon Aug 08 07:00:00 UTC 2016 >= Tue Aug 09 00:00:00 UTC 2016 ?
Q3:
I tried to specify TZ as part of Spring Context:
<bean id="defaultZoneInfo" class="sun.util.calendar.ZoneInfo" factory-method="getTimeZone">
<constructor-arg type="java.lang.String" value="UTC"/>
</bean>
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="java.util.TimeZone.setDefault"/>
<property name="arguments">
<list>
<ref bean="defaultZoneInfo"/>
</list>
</property>
</bean>
but the result was the same as with Q2.
Q4:
Specify TZ in static block:
static {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
}
and test - passed!
Records in H2 db:
Mon Aug 08 00:00:00 UTC 2016
Thu Oct 20 00:00:00 UTC 2016
Thu Oct 20 00:00:00 UTC 2016
Current Date is: Tue Aug 09 00:00:00 UTC 2016
Thu Oct 20 00:00:00 UTC 2016
Thu Oct 20 00:00:00 UTC 2016
So, can someone explain why specifying default TZ in Spring Context xml file and directly in test method didn't fix problem?
And only specifying TZ via static block solved the problem?

I think it may be your database problem not your application
for example Oracle database not accept connection from client after changing Client location in control panel.

Related

Spring Crontab pattern: every weekday at specific times

Here is the documentation for the Spring Crontab syntax.
I want to run a task every weekday at 14:40, 14:45, 14:50, 14:55, and 15:00, but I can't figure out how to express this with a Crontab pattern. The closest I've come up with so far is:
0 40/5 14 * * MON-FRI
But this doesn't run at 15:00.
Is this possible to express with a Crontab pattern at all?
You need to split it into two expressions :
0 40-55/5 14 * * MON-FRI
0 0 15 * * MON-FRI
If you only want to have one expression and you are okay with the last trigger time in a day run one minute before, you can use :
0 40-55/5,59 14 * * MON-FRI
Spring internally use CronSequenceGenerator to generate the next trigger time for a cron expression. You can use it to verify a cron expression.
For example , to verify the next several trigger times of 0 40-55/5,59 14 * * MON-FRI:
CronSequenceGenerator generator = new CronSequenceGenerator("0 40-55/5,59 14 * * MON-FRI");
Date d = Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant());
for (int i = 0; i < 10; i++) {
d = generator.next(d);
System.out.println(d);
}
which will print out :
Tue Jun 02 14:40:00 HKT 2020
Tue Jun 02 14:45:00 HKT 2020
Tue Jun 02 14:50:00 HKT 2020
Tue Jun 02 14:55:00 HKT 2020
Tue Jun 02 14:59:00 HKT 2020
Wed Jun 03 14:40:00 HKT 2020
Wed Jun 03 14:45:00 HKT 2020
Wed Jun 03 14:50:00 HKT 2020
Wed Jun 03 14:55:00 HKT 2020
Wed Jun 03 14:59:00 HKT 2020

Javamail IMAP - Searching mail by date returning wrong results

Im trying to get emails of a certain date from an inbox in outlook using IMAP, but im getting emails from dates that dont correspond to the date im using for my search, my code is the following:
SimpleDateFormat df1 = new SimpleDateFormat( "MM/dd/yy" );
String dt="10/02/18";
java.util.Date dDate = df1.parse(dt);
/*
Connection code to the email goes here
*/
SearchTerm st = new ReceivedDateTerm(ComparisonTerm.EQ,dDate);
IMAPFolder inbox = (IMAPFolder) store.getFolder("INBOX");
inbox.open(Folder.READ_WRITE);
Message[] messages = inbox.search(st);
int total = messages.length;
/* RESULTS */
println("\nTotal_Email = " + messages.length);
for (int index = 0; index < total; index++) {
Date date=message.getReceivedDate();
System.out.println("DATE RECEIVED="+date);
}
Im getting the following result when I use the date "10/01/18"
Total_Email = 5
DATE RECEIVED=Mon Oct 01 17:45:44 COT 2018
DATE RECEIVED=Mon Oct 01 16:43:27 COT 2018
DATE RECEIVED=Mon Oct 01 16:17:11 COT 2018
DATE RECEIVED=Mon Oct 01 15:37:38 COT 2018
DATE RECEIVED=Mon Oct 01 14:53:48 COT 2018
And then Im getting the following result when I use the date "10/02/18"
Total_Email = 6
DATE RECEIVED=Tue Oct 02 08:09:53 COT 2018
DATE RECEIVED=Mon Oct 01 23:21:34 COT 2018
DATE RECEIVED=Mon Oct 01 22:37:22 COT 2018
DATE RECEIVED=Mon Oct 01 21:33:37 COT 2018
DATE RECEIVED=Mon Oct 01 20:21:20 COT 2018
DATE RECEIVED=Mon Oct 01 19:11:50 COT 2018
My guess is that it has to do with my timezone, I live in Colombia and my timezone is GMT-5, Is there any way to fix and get the correct results ?
No, IMAP is not timezone aware, and it is server specific what timezone it computes and reports the results in. You may need to request more than you need and do client side filtering.
Most of the large multinational servers use UTC for convenience, so you'd have to fetch the two days overlapping the period you're interested in.

Calender.YEAR not printing the right value

I'm parsing the Date that received from user query and another date from XML file.
When I want to get just the YEAR, it print 1 instead of year, by using:
calender.YEAR
This is the code:
Elements date = doc.getElementsByTag("DATE");
DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
Date inputDate = dateFormat.parse(obj.tryParse(dateFrom));
Date xmlDate = dateFormat.parse(obj.tryParse(date.get(0).text()));
Calendar calInput = Calendar.getInstance();
Calendar calXml = Calendar.getInstance();
calInput.setTime(inputDate);
calXml.setTime(xmlDate);
System.out.println(calInput.YEAR +" "+ calXml.YEAR +" = "+calInput.getTime().toString()+"|||"+ calXml.getTime().toString());
if(calInput.YEAR != calXml.YEAR)
continue;
And this is a sample of the output:
Info: 1 1 = Wed Jan 01 00:00:00 IST 2003|||Tue Jan 01 00:00:00 IST 2002
Info: 1 1 = Wed Jan 01 00:00:00 IST 2003|||Tue Jan 01 00:00:00 IST 2002
Info: 1 1 = Wed Jan 01 00:00:00 IST 2003|||Tue Jan 01 00:00:00 IST 2002
Info: 1 1 = Wed Jan 01 00:00:00 IST 2003|||Tue Jan 01 00:00:00 IST 2002
Info: 1 1 = Wed Jan 01 00:00:00 IST 2003|||Tue Jan 01 00:00:00 IST 2002
Info: 1 1 = Wed Jan 01 00:00:00 IST 2003|||Tue Jan 01 00:00:00 IST 2002
Info: 1 1 = Wed Jan 01 00:00:00 IST 2003|||Tue Jan 01 00:00:00 IST 2002
Info: 1 1 = Wed Jan 01 00:00:00 IST 2003|||Tue Jan 01 00:00:00 IST 2002
Info: 1 1 = Wed Jan 01 00:00:00 IST 2003|||Tue Jan 01 00:00:00 IST 2002
Info: 1 1 = Wed Jan 01 00:00:00 IST 2003|||Tue Jan 01 00:00:00 IST 2002
Info: 1 1 = Wed Jan 01 00:00:00 IST 2003|||Sun Feb 01 00:00:00 IST 2004
Info: 1 1 = Wed Jan 01 00:00:00 IST 2003|||Mon Apr 01 00:00:00 IDT 2002
Info: 1 1 = Wed Jan 01 00:00:00 IST 2003|||Mon Apr 01 00:00:00 IDT 2002
Info: 1 1 = Wed Jan 01 00:00:00 IST 2003|||Mon Apr 01 00:00:00 IDT 2002
Info: 1 1 = Wed Jan 01 00:00:00 IST 2003|||Mon Apr 01 00:00:00 IDT 2002
Info: 1 1 = Wed Jan 01 00:00:00 IST 2003|||Mon Apr 01 00:00:00 IDT 2002
Info: 1 1 = Wed Jan 01 00:00:00 IST 2003|||Mon Apr 01 00:00:00 IDT 2002
Info: 1 1 = Wed Jan 01 00:00:00 IST 2003|||Mon Apr 01 00:00:00 IDT 2002
Info: 1 1 = Wed Jan 01 00:00:00 IST 2003|||Mon Apr 01 00:00:00 IDT 2002
calXml.YEAR should be written Calendar.YEAR, because it is a constant (public static final) value to be used as a parameter to methods like get(int field) and add(int field, int amount).
To get the year, call calXml.get(Calendar.YEAR).
The Answer by Andreas is correct.
java.time
Alternatively, you can use the new java.time framework built into Java 8 and later. The old date-time classes are a mess and should be avoided.
Convert from java.util.Date to java.time.Instant. An Instant is a moment on the timeline in UTC.
Instant instant = yourJavaUtilDate.toInstant();
Apply a time zone. Your Question's code implicitly depends on the JVM’s current default time zone. I suggest that it is better to explicitly specify your desired/expected time zone. The time zone is critical in determining a date and therefore the year.
ZoneId zoneId = ZoneId.of( "Asia/Kolkata" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
Now we can extract the year number.
int year = zdt.getYear();
Or more interesting, we can get a Year object.
Year year = Year.from( zdt );
Boolean isLeapYear = year.isLeap();
int yearNumber = year.getValue();

Java Calendar bug?

After a lot of debugging I narrowed my problem to the following snippet:
public static void calendarBug() {
for (int i=0 ; i<6 ; i++) {
Calendar c = Calendar.getInstance();
c.clear();
c.set(2015, 2, 27, i, 0);
System.out.println(c.getTime());
}
}
Running this gives the following output:
Fri Mar 27 00:00:00 IST 2015
Fri Mar 27 01:00:00 IST 2015
Fri Mar 27 03:00:00 IDT 2015
Fri Mar 27 03:00:00 IDT 2015
Fri Mar 27 04:00:00 IDT 2015
Fri Mar 27 05:00:00 IDT 2015
Does anyone know why does c.set(2015,2,27,2,0) returns 3AM instead of 2AM?
Think about that your are at time just at DST time, It moves forward one hour or moves back one hour without living this time portion.
So It is not bug, it is feature.
When you change the timezone which does not use DST (lets say Canada/East-Saskatchewan), you will see what you have expected.
Here is an example.
public static void calendarBug() {
for (int i=0 ; i<6 ; i++) {
Calendar c = Calendar.getInstance();
c.setTimeZone(TimeZone.getTimeZone("Canada/East-Saskatchewan"));
c.clear();
c.set(2015, 2, 27, i, 0);
System.out.println(c.getTime());
}
}
Fri Mar 27 08:00:00 EET 2015
Fri Mar 27 09:00:00 EET 2015
Fri Mar 27 10:00:00 EET 2015
Fri Mar 27 11:00:00 EET 2015
Fri Mar 27 12:00:00 EET 2015
Fri Mar 27 13:00:00 EET 2015
That is most likely a DST switchover for your timezone.
Mar 27 is the last Friday of March in 2015. This is the day when the DST switchover takes place in the Israel, Jordan, Syria, the West Bank etc.
See
Daylight Savings Time
Daylight Savings Time by Country
Daylight Saving Time Dates - 2014/2015

Subtracting dates in Java. Daylight Savings Time Changes

The problem is that the subtraction of the two dates leaves me double identical value.
From : Thu Nov 29 00:00:00 CET 2012
Value 121: To: Sat Mar 30 00:00:00 CET 2013
Value 122: To: Sun Mar 31 00:00:00 CET 2013
Value 122: To: Mon Apr 01 00:00:00 CEST 2013
Value 123: To: Tue Apr 02 00:00:00 CEST 2013
Long today = (To.getTime() - From.getTime()) / (1000 * 60 * 60 * 24);
Is it possible to somehow avoid that logically? (sorry for English)

Categories

Resources