0

I am pragmatically building a nested JSON from a table. Json looks something like this:

{"date":"03-16-2018 06:57:02",
 "details":
    [  
        {  
           "motorstate":0,
           "startTime":"03-16-2018 20:41:57",               
        },
        {  
           "motorstate":0,
           "startTime":"03-16-2018 06:57:02",               
        }
     ]
},
{"date":"03-15-2018 08:08:48",
"details":
   [  
        {  
           "motorstate":0,
           "startTime":"03-16-2018 03:53:30",
        }
   ]
}

If you look into the above example, the second record:

{"date":"03-15-2018 08:08:48",
"details":
   [  
        {  
           "motorstate":0,
           "startTime":"03-16-2018 03:53:30",
        }
   ]
}

The dates are mismatching. This is because the date shown here is in IST but actually stored in UTC in my Google Datastore. In UTC, its still 03-15-2018 and not 03-16-2018.

My question is how can we perform a date difference in different timezones other than UTC in Java? The Date.getTime() method always give the difference in UTC and not in local Timezone.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
Sandy
  • 79
  • 2
  • 8
  • You can convert your local timezone to UTC format and then send. Let me know if it works – Divya Mar 17 '18 at 08:37
  • Why should i convert it to UTC, the method Date.getTime() already returns the result in UTC and not local time zone.. which always return 03-15-2018 where my local date is 03-16-2018, that creates a problem in my logic since i am building this nested json based on the day of the date. Please note the time 03:53:30 which is less than 05:30:00 (IST time).. so the date return is always 03-15-2018 and not 03-16-2018 – Sandy Mar 17 '18 at 08:49
  • Try specifying your timezone to the date you are setting and then check. – Divya Mar 17 '18 at 08:54
  • pasted the code. below – Sandy Mar 17 '18 at 09:03
  • Your Question and Title meanders. Can you edit to be more specific? – Basil Bourque Mar 17 '18 at 16:55

3 Answers3

3

tl;dr

Date difference in different timezones in java

Period.between(
    LocalDateTime.parse(
         "03-15-2018 08:08:48" , 
         DateTimeFormatter.ofPattern( “MM-dd-uuuu HH:mm:ss” )
    )
    .atZone( ZoneId.of( ”Asia/Kolkata" )  ) 
    .toLocalDate()
    ,
    LocalDate.now( ZoneId.of( ”Asia/Kolkata" ) )
)

Details

The modern approach uses the java.time classes rather than the troublesome old me old legacy date-time classes such as Date and Calendar.

Tip: Avoid custom formatting patterns when serializing date-time values to text. Use standard ISO 8601 formats only.

Tip: when exchanging date-time values as text, always include an indicator of the offset-from-UTC and the time zone name.

First, parse your input strings as LocalDateTime because they lack any indication of offset or zone.

Define a formatting pattern to match input.

DateTimeFormatter f = DateTimeFormatter.ofPattern( “MM-dd-uuuu HH:mm:ss” ) ;

Parse.

String input = "03-15-2018 08:08:48" ;
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;

You claim to know that these inputs were intended to represent a moment in India time. Apply a ZoneId to get a ZonedDateTime.

ZoneId z = ZoneId.of( ”Asia/Kolkata" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;

To get the date-only value, extract a LocalDate.

LocalDate ld = zdt.toLocalDate() ; 

To represent the delta between dates as a number of years, months, and days unattached to the timeline, use Period.

Period p = Period.between( ldt , LocalDate.now( z ) ) ;

For a count of total days.

long days = ChronoUnit.DAYS.between( start , stop ) ;

About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
0

Below method will return you your UTC time to current Timezone and this worked for me

  public static Date getLocalDateObjFromUTC(String date, String time) throws ParseException {
    String dateAndTimeInUTC = date + " " + time;
    SimpleDateFormat localDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
    localDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
    Date dateInLocalTimeZone = localDateFormat.parse(dateAndTimeInUTC);
    return dateInLocalTimeZone;
}
Divya
  • 121
  • 2
  • 11
  • This converts Local to UTC, i am looking to convert UTC to Local and then perform a date difference. Please understand the question. – Sandy Mar 17 '18 at 08:54
  • Can you post your code where you are trying to do so or else try setting your df.setTimeZone(TimeZone.getDefault()); – Divya Mar 17 '18 at 08:55
  • done... check the code after statement if(pe!=null) – Sandy Mar 17 '18 at 09:06
  • You need to mention that the timezone you are getting is UTC not IST. It will convert it to your local time automattically after parsing. – Divya Mar 17 '18 at 09:11
  • Thanks ! this method will return an object in Date format. If i call the method .getTime() of this Date object, it will always return UTC time in long format. My problem is not conversion, but date difference after conversion.. – Sandy Mar 17 '18 at 09:53
  • 1
    The troublesome classes used here became legacy years ago, now supplanted by the *java.time* classes. – Basil Bourque Mar 17 '18 at 15:41
  • Please don’t teach the young ones to use the long outdated and notoriously troublesome `SimpleDateFormat` class. At least not as the first option. And not without any reservation. Today we have so much better in [`java.time`, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Mar 17 '18 at 15:47
0
public String getSummary(String deviceGuid)
{
    Query<com.google.cloud.datastore.Entity> query 
        = Query.newEntityQueryBuilder()
            .setKind("sensordata")
            .setFilter(PropertyFilter.eq("deviceguid", deviceGuid))
            .setOrderBy(OrderBy.desc("startTime"))
            .build();

    QueryResults<com.google.cloud.datastore.Entity> resultList = 
  datastore.run(query);
    if(!resultList.hasNext())
    {           
        log.warning("No record found..");
        return "No record found";
    }

    com.google.cloud.datastore.Entity e =null;
    com.google.cloud.datastore.Entity pe =null;

    SensorDataOut sensorDataOut = new SensorDataOut();
    SensorSummaryDataOut summary = new SensorSummaryDataOut();
    TotalSummaryDataOut totalSummary = new TotalSummaryDataOut();


    Calendar calendar = Calendar.getInstance();
    calendar.setTimeZone(TimeZone.getTimeZone("IST"));

    Calendar calendar1 = Calendar.getInstance();
    calendar1.setTimeZone(TimeZone.getTimeZone("IST"));


    SimpleDateFormat sdf = new SimpleDateFormat("MM-dd-yyyy HH:mm:ss");
    sdf.setTimeZone(TimeZone.getTimeZone("IST"));

    SimpleDateFormat sdf1 = new SimpleDateFormat("MM-dd-yyyy");
    //sdf.setTimeZone(TimeZone.getTimeZone("IST"));



    long stopTime;
    long startTime;
    long pStartTime;
    long diffTime;
    long diffDay;
    Date pDateWithoutTime;
    Date eDateWithoutTime;

    while(resultList.hasNext())
    {
        e = resultList.next();

        startTime  = (e.contains("startTime"))?e.getTimestamp("startTime").toSqlTimestamp().getTime():0;
        stopTime  = (e.contains("stopTime"))?e.getTimestamp("stopTime").toSqlTimestamp().getTime():0;   
        //log.info("Start Date : " + e.getTimestamp("startTime").toString() + " - " +  String.valueOf(startTime));
        //log.info("Stop Date : " + e.getTimestamp("stopTime").toString() + " - " + String.valueOf(stopTime));
        //log.info("Usage Volume :" + String.valueOf(e.getLong("usageVolume")));

        sensorDataOut = new SensorDataOut();

        calendar.setTimeInMillis(stopTime);                                             
        sensorDataOut.stopTime = sdf.format(calendar.getTime());

        calendar.setTimeInMillis(startTime);                                    
        sensorDataOut.startTime = sdf.format(calendar.getTime());


        sensorDataOut.motorstate    = (e.contains("motorstate"))?(int)e.getLong("motorstate"):-1;
        sensorDataOut.startVolume   = (e.contains("startVolume"))?(int)e.getLong("startVolume"):-1;
        sensorDataOut.stopVolume    = (e.contains("stopVolume"))?(int)e.getLong("stopVolume"):-1;
        sensorDataOut.usageTime     = (e.contains("usageTime"))?e.getLong("usageTime"):-1;
        sensorDataOut.usageVolume   = (e.contains("usageVolume"))?(int)e.getLong("usageVolume"):-1;

        if(pe!=null)
        {               
            //Get the date difference in terms of days. If it is same day then add the volume consumed
            pStartTime= pe.getTimestamp("startTime").toSqlTimestamp().getTime();
            try{
                calendar.setTimeInMillis(pStartTime);
                pDateWithoutTime = sdf1.parse(sdf1.format(calendar.getTime()));

                calendar1.setTimeInMillis(e.getTimestamp("startTime").toSqlTimestamp().getTime());
                eDateWithoutTime = sdf1.parse(sdf1.format(calendar1.getTime()));    


            }
            catch(Exception ex){
                log.info("Exception while parsing date");
                continue;
            }


            diffTime = Math.abs(pDateWithoutTime.getTime() - eDateWithoutTime.getTime());
            diffDay = TimeUnit.DAYS.convert(diffTime, TimeUnit.MILLISECONDS);


            //log.info("pDateWithoutTime: " + pDateWithoutTime +  ", eDateWithoutTime: " + eDateWithoutTime + ", consumedVolume: " 
            //          + sensorDataOut.usageVolume;


            if(diffDay!=0) //If not same day
            {
                totalSummary.totVolume = totalSummary.totVolume + summary.totVolume;
                totalSummary.totDuration = totalSummary.totDuration + summary.totDuration;                  
                totalSummary.details.add(summary);
                summary = new SensorSummaryDataOut();                   
            }

        }

        summary.date = sensorDataOut.startTime;         
        summary.totVolume = summary.totVolume + sensorDataOut.usageVolume;
        summary.totDuration = summary.totDuration + sensorDataOut.usageTime;            
        summary.details.add(sensorDataOut);

        pe = e;
    }

    if(summary.details.size()>0)
    {
        totalSummary.totVolume = totalSummary.totVolume + summary.totVolume;
        totalSummary.totDuration = totalSummary.totDuration + summary.totDuration;                  
        totalSummary.details.add(summary);
        summary = new SensorSummaryDataOut();                   
    }

    totalSummary.avgVolume = totalSummary.totVolume/totalSummary.details.size();
    totalSummary.deviceguid = deviceGuid;

    String json = "";
    Gson gson = new Gson();
    json = gson.toJson(totalSummary);
    return json;

} //End of Function
Sandy
  • 79
  • 2
  • 8
  • 1
    Please don’t teach the young ones to use the long outdated and notoriously troublesome `SimpleDateFormat` class. At least not as the first option. And not without any reservation. Today we have so much better in [`java.time`, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Mar 17 '18 at 15:46