1

I'm parsing a comma delimited file that has two field I need to convert to a timestamp. I get a date, and a separate field gives me minutes passed midnight... for instance:

10/15/2020, 360

now 360, for most days, would be 6am (360/60 = 6) but on DST says it could be either 5 or 7. The problem is I'm always expected to output 6am even when it's a DST day.

Calendar cal = Calendar.getInstance();
cal.setTime(schedDate);

cal.add(Calendar.MINUTE, Integer.parseInt(minutes));

return new Timestamp(cal.getTimeInMillis());

I've tried adding the following:

cal.set(cal.DST_OFFSET, 0);

but that doesn't seem to fix the issue. I'm not sure if calendar has any built in functionality to disable DST offsets, but any suggestions would be appreciated

MatthewC
  • 41
  • 7
  • On which time zone or offset does this depend? The one of the system or some fixed one? – deHaar Oct 09 '20 at 14:35
  • Any I guess? I'm taking the system default but no matter what timezone it's running in, I'd want 360 to equal 6am every day of the year. – MatthewC Oct 09 '20 at 15:05
  • Then use the answer given by @ArvindKumarAvinash or my one... Both are adding the minutes to the date parsed in order to get the desired time of day. – deHaar Oct 09 '20 at 15:16
  • 1
    I recommend you neither use `Calendar` nor `java.sql.Timestamp`. Those classes are poorly designed and long outdated, the former in particular notoriously troublesome. Instead use classes from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Oct 09 '20 at 15:25

3 Answers3

3

Use LocalDateTime which does not have to deal with time-zone (and hence DST). Note that LocalDateTime is part of the modern date-time API.

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        LocalDateTime ldt = LocalDate.parse("10/15/2020", DateTimeFormatter.ofPattern("M/d/u")).atStartOfDay()
                .plusHours(6);
        System.out.println(ldt);
    }
}

Output:

2020-10-15T06:00

I also suggest you stop using the error-prone and outdated java.util date-time API.

If you are doing it for your Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Learn more about the modern date-time API at Trail: Date Time.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
2

Using java.time, you can involve the time zone of the system or give it a fixed one.

The following code shows how you could do that:

public static void main(String[] args) {
    // example input
    String date = "10/15/2020";
    long minutes = 360;
    // create a LocalDate from the String considering its format
    LocalDate localDate = LocalDate.parse(date, DateTimeFormatter.ofPattern("MM/dd/uuuu"));
    // create a minimum LocalTime (the beginning of a day) and add the minutes you got
    LocalTime timeOfDay = LocalTime.MIN.plusMinutes(minutes);
    // create a zone-aware object by using the date, the time of day and the system's zone
    ZonedDateTime zonedDateTime = ZonedDateTime.of(localDate,
                                                    timeOfDay, 
                                                    ZoneId.systemDefault());
    // print the toString() method (implicitly)
    System.out.println(zonedDateTime);
    // or use a custom format
    System.out.println(zonedDateTime.format(DateTimeFormatter
                                            .ofPattern("MM/dd/uuuu HH:mm:ss")));
}

It outputs the following (which was run on a system with UTC+2):

2020-10-15T06:00+02:00[Europe/Berlin]
10/15/2020 06:00:00
deHaar
  • 17,687
  • 10
  • 38
  • 51
2

Now we’re at it, we can let java.time parse both fields from the CSV file (comma separated values file) and combine them:

        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("M/d/u");
        DateTimeFormatter minuteOfDayFormatter = new DateTimeFormatterBuilder()
                .appendValue(ChronoField.MINUTE_OF_DAY)
                .toFormatter();
        
        String dateString = "10/15/2020";
        String timeString = "360";
        
        LocalDate date = LocalDate.parse(dateString, dateFormatter);
        LocalTime time = LocalTime.parse(timeString, minuteOfDayFormatter);
        LocalDateTime dateTime = date.atTime(time);
        
        System.out.println(dateTime);

Output is:

2020-10-15T06:00

If you thought you needed a java.sql.Timestamp for your SQL database, you most probably don’t. You may pass the LocalDateTime object to your database using for example PreparedStatement.setObject(). If you need to control the time zone (usually a good idea), convert it to OffsetDateTime or Instant first. Search for how.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • 1
    This is exactly what I did after reading both Arvind and deHaar's responses! Thanks for making me feel like I'm on the right path haha. – MatthewC Oct 09 '20 at 15:37