All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opentripplanner.util.time.DateUtils Maven / Gradle / Ivy

package org.opentripplanner.util.time;

import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.List;
import javax.annotation.Nonnull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Frank Purcell (p u r c e l l f @ t r i m e t . o r g) October 20, 2009
 */
public class DateUtils {

  private static final Logger LOG = LoggerFactory.getLogger(DateUtils.class);

  private static final int SANITY_CHECK_CUTOFF_YEAR = 1000;

  // NOTE: don't change the order of these strings...the simplest should be on the
  // bottom...you risk parsing the wrong thing (and ending up with year 0012)
  private static final List DF_LIST = List.of(
    DateTimeFormatter.ofPattern("yyyy.MM.dd.HH.mm.ss"),
    DateTimeFormatter.ofPattern("yyyy.MM.dd.HH.mm"),
    DateTimeFormatter.ofPattern("yyyy.MM.dd.HH.mm.ss.SS"),
    DateTimeFormatter.ofPattern("M.d.yy h.mm a"),
    DateTimeFormatter.ofPattern("M.d.yyyy h.mm a"),
    DateTimeFormatter.ofPattern("M.d.yyyy h.mma"),
    DateTimeFormatter.ofPattern("M.d.yyyy h.mm"),
    DateTimeFormatter.ofPattern("M.d.yyyy k.mm"),
    DateTimeFormatter.ofPattern("M.d.yyyy"),
    DateTimeFormatter.ofPattern("yyyy.M.d"),
    DateTimeFormatter.ofPattern("h.mm a")
    // NOTE: don't change the order of these strings...the simplest should be on the
    // bottom...you risk parsing the wrong thing (and ending up with year 0012)
  );

  private static final List SMALL_DF_LIST = List.of(
    DateTimeFormatter.ofPattern("M.d.yy"),
    DateTimeFormatter.ofPattern("yy.M.d"),
    DateTimeFormatter.ofPattern("h.mm a")
  );

  /**
   * Returns a Date object based on input date and time parameters Defaults to today / now (when
   * date / time are null)
   */
  public static ZonedDateTime toZonedDateTime(String date, String time, ZoneId tz) {
    //LOG.debug("JVM default timezone is {}", TimeZone.getDefault());
    LOG.debug("Parsing date {} and time {}", date, time);
    LOG.debug("using timezone {}", tz);
    ZonedDateTime retVal = ZonedDateTime.ofInstant(Instant.now(), tz);
    if (date != null) {
      LocalDate localDate = parseDate(date);
      if (localDate == null) {
        return null; //unparseable date
      }
      boolean timed = false;
      if (time != null) {
        LocalTime localTime = parseTime(time);
        if (localTime != null) {
          retVal = LocalDateTime.of(localDate, localTime).atZone(tz);
          timed = true;
        }
      }
      if (!timed) {
        //assume t = now
        retVal = LocalDateTime.of(localDate, retVal.toLocalTime()).atZone(tz);
      }
    } else if (time != null) {
      LocalTime localTime = parseTime(time);
      if (localTime != null) {
        retVal = LocalDateTime.of(retVal.toLocalDate(), localTime).atZone(tz);
      }
    }
    LOG.debug("resulting date is {}", retVal);
    return retVal;
  }

  // TODO: could be replaced with Apache's DateFormat.parseDate ???
  public static LocalDate parseDate(@Nonnull String input) {
    LocalDate retVal = null;
    try {
      String newString = input
        .trim()
        .replace('_', '.')
        .replace('-', '.')
        .replace(':', '.')
        .replace('/', '.');
      List dateTimeFormatterList = DF_LIST;

      if (newString.length() <= 8) {
        if (newString.matches("\\d\\d\\d\\d\\d\\d\\d\\d")) {
          // Accept dates without punctuation if they consist of exactly eight digits.
          newString =
            newString.substring(0, 4) +
            '.' +
            newString.substring(4, 6) +
            '.' +
            newString.substring(6, 8);
        } else if (!(newString.matches(".*20\\d\\d.*"))) {
          // if it looks like we have a small date format, ala 11.4.09, then use
          // another set of compares
          dateTimeFormatterList = SMALL_DF_LIST;
        }
      }

      for (DateTimeFormatter dateTimeFormatter : dateTimeFormatterList) {
        try {
          retVal = LocalDate.parse(newString, dateTimeFormatter);
          if (retVal != null) {
            int year = retVal.getYear();
            if (year >= SANITY_CHECK_CUTOFF_YEAR) {
              break;
            }
          }
        } catch (DateTimeParseException ex) {}
      }
    } catch (Exception ex) {
      throw new RuntimeException("Could not parse " + input);
    }

    return retVal;
  }

  public static int getIntegerFromString(String input) {
    try {
      return Integer.parseInt(input);
    } catch (Exception e) {
      return 0;
    }
  }

  /**
   * Converts the given time in seconds to a String in the format h:mm.
   *
   * @param seconds the time in seconds.
   * @return a String representing the time in the format h:mm
   */
  public static String secToHHMM(int seconds) {
    int min;
    String sign = "";

    if (seconds >= 0) {
      min = seconds / 60;
      sign = "";
    } else {
      min = -seconds / 60;
      sign = "-";
    }

    int mm = min % 60;
    int hh = min / 60;

    return String.format("%s%d:%02d", sign, hh, mm);
  }

  public static String trim(String str) {
    String retVal = str;
    try {
      retVal = str.trim();
      retVal = retVal.replaceAll("%20;", "");
      retVal = retVal.replaceAll("%20", "");
    } catch (Exception ex) {}
    return retVal;
  }

  public static long absoluteTimeout(Duration timeout) {
    if (timeout == null) {
      return Long.MAX_VALUE;
    } else {
      return System.currentTimeMillis() + timeout.toMillis();
    }
  }

  private static LocalTime parseTime(String time) {
    boolean amPm = false;
    int addHours = 0;
    int hour = 0, min = 0, sec = 0;
    try {
      String[] hms = time.toUpperCase().split(":");

      // if we don't have a colon sep string, assume string is int and represents seconds past
      // midnight
      if (hms.length < 2) {
        return LocalTime.ofSecondOfDay(getIntegerFromString(time));
      }

      if (hms[1].endsWith("PM") || hms[1].endsWith("AM")) {
        amPm = true;

        if (hms[1].contains("PM")) addHours = 12;

        int suffex = hms[1].lastIndexOf(' ');
        if (suffex < 1) {
          suffex = hms[1].lastIndexOf("AM");
          if (suffex < 1) {
            suffex = hms[1].lastIndexOf("PM");
          }
        }
        hms[1] = hms[1].substring(0, suffex);
      }

      int h = Integer.parseInt(trim(hms[0]));
      if (amPm && h == 12) h = 0;
      hour = h + addHours;

      min = Integer.parseInt(trim(hms[1]));
      if (hms.length > 2) {
        sec = Integer.parseInt(trim(hms[2]));
      }

      return LocalTime.of(hour, min, sec);
    } catch (Exception ignore) {
      LOG.info("Time '{}' didn't parse", time);
      return null;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy