/** * Copyright (c) 2010-2017 by the respective copyright holders. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.eclipse.smarthome.binding.astro.internal.util; import java.util.Calendar; import java.util.Date; import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.time.DateUtils; import org.eclipse.smarthome.binding.astro.internal.config.AstroChannelConfig; import org.eclipse.smarthome.binding.astro.internal.model.Range; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Common used DateTime functions. * * @author Gerhard Riegler - Initial contribution */ public class DateTimeUtils { private static final Logger logger = LoggerFactory.getLogger(DateTimeUtils.class); private static final Pattern HHMM_PATTERN = Pattern.compile("^([0-1][0-9]|2[0-3])(:[0-5][0-9])$"); public static final double J1970 = 2440588.0; public static final double MILLISECONDS_PER_DAY = 1000 * 60 * 60 * 24; /** * Truncates the time from the calendar object. */ public static Calendar truncateToMidnight(Calendar calendar) { return DateUtils.truncate(calendar, Calendar.DAY_OF_MONTH); } /** * Creates a Range object within the specified months and days. The start * time is midnight, the end time is end of the day. */ public static Range getRange(int startYear, int startMonth, int startDay, int endYear, int endMonth, int endDay) { Calendar start = Calendar.getInstance(); start.set(Calendar.YEAR, startYear); start.set(Calendar.MONTH, startMonth); start.set(Calendar.DAY_OF_MONTH, startDay); start = truncateToMidnight(start); Calendar end = Calendar.getInstance(); end.set(Calendar.YEAR, endYear); end.set(Calendar.MONTH, endMonth); end.set(Calendar.DAY_OF_MONTH, endDay); end.set(Calendar.HOUR_OF_DAY, 23); end.set(Calendar.MINUTE, 59); end.set(Calendar.SECOND, 59); end.set(Calendar.MILLISECOND, 999); return new Range(start, end); } /** * Returns a calendar object from a julian date. */ public static Calendar toCalendar(double julianDate) { if (Double.compare(julianDate, Double.NaN) == 0 || julianDate == 0) { return null; } long millis = (long) ((julianDate + 0.5 - J1970) * MILLISECONDS_PER_DAY); Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(millis); return DateUtils.round(cal, Calendar.MINUTE); } /** * Returns the julian date from the calendar object. */ public static double dateToJulianDate(Calendar calendar) { return calendar.getTimeInMillis() / MILLISECONDS_PER_DAY - 0.5 + J1970; } /** * Returns the midnight julian date from the calendar object. */ public static double midnightDateToJulianDate(Calendar calendar) { return dateToJulianDate(truncateToMidnight(calendar)); } /** * Returns the end of day julian date from the calendar object. */ public static double endOfDayDateToJulianDate(Calendar calendar) { Calendar cal = (Calendar) calendar.clone(); cal = DateUtils.ceiling(cal, Calendar.DATE); cal.add(Calendar.MILLISECOND, -1); return dateToJulianDate(cal); } /** * Returns the year of the calendar object as a decimal value. */ public static double getDecimalYear(Calendar calendar) { return calendar.get(Calendar.YEAR) + (double) calendar.get(Calendar.DAY_OF_YEAR) / calendar.getActualMaximum(Calendar.DAY_OF_YEAR); } /** * Converts the time (hour.minute) to a calendar object. */ public static Calendar timeToCalendar(Calendar calendar, double time) { if (time < 0.0) { return null; } Calendar cal = (Calendar) calendar.clone(); int hour = 0; int minute = 0; if (time == 24.0) { cal.add(Calendar.DAY_OF_MONTH, 1); } else { hour = (int) time; minute = (int) ((time * 100) - (hour * 100)); } cal.set(Calendar.HOUR_OF_DAY, hour); cal.set(Calendar.MINUTE, minute); return DateUtils.truncate(cal, Calendar.MINUTE); } /** * Returns true, if two calendar objects are on the same day ignoring time. */ public static boolean isSameDay(Calendar cal1, Calendar cal2) { return cal1 != null && cal2 != null && DateUtils.isSameDay(cal1, cal2); } /** * Returns a date object from a calendar. */ public static Date getDate(Calendar calendar) { return calendar == null ? null : calendar.getTime(); } /** * Returns the next Calendar from today. */ public static Calendar getNext(Calendar... calendars) { Calendar now = Calendar.getInstance(); Calendar next = null; for (Calendar calendar : calendars) { if (calendar.after(now) && (next == null || calendar.before(next))) { next = calendar; } } return next; } /** * Returns true, if cal1 is greater or equal than cal2, ignoring seconds. */ public static boolean isTimeGreaterEquals(Calendar cal1, Calendar cal2) { Calendar truncCal1 = DateUtils.truncate(cal1, Calendar.MINUTE); Calendar truncCal2 = DateUtils.truncate(cal2, Calendar.MINUTE); return truncCal1.getTimeInMillis() >= truncCal2.getTimeInMillis(); } /** * Applies the config to the given calendar. */ public static Calendar applyConfig(Calendar cal, AstroChannelConfig config) { Calendar cCal = cal; if (config.getOffset() != null && config.getOffset() != 0) { Calendar cOffset = Calendar.getInstance(); cOffset.setTime(cCal.getTime()); cOffset.add(Calendar.MINUTE, config.getOffset()); cCal = cOffset; } Calendar cEarliest = adjustTime(cCal, getMinutesFromTime(config.getEarliest())); if (cCal.before(cEarliest)) { return cEarliest; } Calendar cLatest = adjustTime(cCal, getMinutesFromTime(config.getLatest())); if (cCal.after(cLatest)) { return cLatest; } return cCal; } private static Calendar adjustTime(Calendar cal, int minutes) { if (minutes > 0) { Calendar cTime = Calendar.getInstance(); cTime = DateUtils.truncate(cal, Calendar.DAY_OF_MONTH); cTime.add(Calendar.MINUTE, minutes); return cTime; } return cal; } /** * Parses a HH:MM string and returns the minutes. */ private static int getMinutesFromTime(String configTime) { String time = StringUtils.trimToNull(configTime); if (time != null) { try { if (!HHMM_PATTERN.matcher(time).matches()) { throw new NumberFormatException(); } else { int hour = Integer.parseInt(StringUtils.substringBefore(time, ":")); int minutes = Integer.parseInt(StringUtils.substringAfter(time, ":")); return (hour * 60) + minutes; } } catch (Exception ex) { logger.warn( "Can not parse astro channel configuration '{}' to hour and minutes, use pattern hh:mm, ignoring!", time); } } return 0; } }