/** * Copyright (C) 2012 52°North Initiative for Geospatial Open Source Software GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.n52.oxf.valueDomains.time; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.TimeZone; /** * @author <a href="mailto:broering@52north.org">Arne Broering</a> */ public class TimeConverter { /** * Converts an input timeInstant in the ISO 8601 form of * 'yyyy-MM-ddTHH:mm:ss+HH:mm' to UTC standard time in the form of * 'yyyy-MM-dd HH:mm:ss' */ public static String convertLocalToUTC(String timeInstant) { TimePosition timePos = (TimePosition) TimeFactory.createTime(timeInstant); String timeZoneOffset = getTimeZoneOffset(timeInstant); Calendar localTime = new GregorianCalendar(TimeZone.getTimeZone("GMT" + timeZoneOffset)); localTime.set(Calendar.YEAR, (int) timePos.getYear()); localTime.set(Calendar.MONTH, timePos.getMonth() - 1); localTime.set(Calendar.DAY_OF_MONTH, timePos.getDay()); localTime.set(Calendar.HOUR_OF_DAY, timePos.getHour()); localTime.set(Calendar.MINUTE, timePos.getMinute()); localTime.set(Calendar.SECOND, (int) timePos.getSecond()); Calendar utcTime = new GregorianCalendar(TimeZone.getTimeZone("UTC")); utcTime.setTimeInMillis(localTime.getTimeInMillis()); int year = utcTime.get(Calendar.YEAR); int month = utcTime.get(Calendar.MONTH) + 1; int day = utcTime.get(Calendar.DAY_OF_MONTH); int hour = utcTime.get(Calendar.HOUR_OF_DAY); int minute = utcTime.get(Calendar.MINUTE); int second = utcTime.get(Calendar.SECOND); return toISO8601(false, year, month, day, hour, minute, second); } /** * Converts an input UTC timeInstant in the form of 'yyyy-MM-dd * HH:mm:ss' to local time indicated by an offset (e.g. '+02' or '-10') to * the ISO8601 form of "yyyy-MM-ddTHH:mm:ss+HH:mm' */ public static String convertUTCToLocal(String timeInstantUTC, String timeZoneOffset) { // Parsing of UTC time: // 0123456789012345678 // yyyy-MM-dd HH:mm:ss Calendar utcTime = new GregorianCalendar(TimeZone.getTimeZone("GMT")); utcTime.set(Calendar.YEAR, Integer.parseInt(timeInstantUTC.substring(0, 4))); utcTime.set(Calendar.MONTH, Integer.parseInt(timeInstantUTC.substring(5, 7)) - 1); utcTime.set(Calendar.DAY_OF_MONTH, Integer.parseInt(timeInstantUTC.substring(8, 10))); utcTime.set(Calendar.HOUR_OF_DAY, Integer.parseInt(timeInstantUTC.substring(11, 13))); utcTime.set(Calendar.MINUTE, Integer.parseInt(timeInstantUTC.substring(14, 16))); utcTime.set(Calendar.SECOND, Integer.parseInt(timeInstantUTC.substring(17, 19))); Calendar localTime = new GregorianCalendar(TimeZone.getTimeZone("GMT" + timeZoneOffset)); localTime.setTimeInMillis(utcTime.getTimeInMillis()); int year = localTime.get(Calendar.YEAR); int month = localTime.get(Calendar.MONTH) + 1; int day = localTime.get(Calendar.DAY_OF_MONTH); int hour = localTime.get(Calendar.HOUR_OF_DAY); int minute = localTime.get(Calendar.MINUTE); int second = localTime.get(Calendar.SECOND); return toISO8601(year, month, day, hour, minute, second, timeZoneOffset); } /** * @param iso8601TimeStamp * an ISO 8601 conform time instnat following the format * 'yyyy-MM-ddTHH:mm:ss+HH:mm'. * @return the time zone offset as a String in format of e.g. '+02:00' */ public static String getTimeZoneOffset(String iso8601TimeInstant) { TimePosition time = new TimePosition(iso8601TimeInstant); String timeZone = time.getTimezone(); if (timeZone.equals("Z")) { return "+00:00"; } return timeZone; } /** * Produces an ISO 8601 representation of the input date variables. * * The output format is either: a) 'yyyy-MM-dd HH:mm:ss' * * or with a 'T' separating date and time: b) 'yyyy-MM-ddTHH:mm:ss' * * @param withTSeparator * indicating whether the separating 'T' shall be present; * otherwise a ' ' separates date and time. * @param year * @param month * 1 = January * @param day * day in month; 1 = 1st day of month * @param hour * 24h mode; 23 = 11 pm * @param minute * @param second */ public static String toISO8601(boolean withTSeparator, int year, int month, int day, int hour, int minute, int second) { String monthString = "" + month; if (month < 10) { monthString = "0" + monthString; } String dayString = "" + day; if (day < 10) { dayString = "0" + dayString; } String hourString = "" + hour; if (hour < 10) { hourString = "0" + hourString; } String minuteString = "" + minute; if (minute < 10) { minuteString = "0" + minuteString; } String secondString = "" + second; if (second < 10) { secondString = "0" + secondString; } if (withTSeparator) { return "" + year + "-" + monthString + "-" + dayString + "T" + hourString + ":" + minuteString + ":" + secondString; } else { return "" + year + "-" + monthString + "-" + dayString + " " + hourString + ":" + minuteString + ":" + secondString; } } /** * Produces an ISO 8601 conform representation of input date variables. * * The output format is: 'yyyy-MM-ddTHH:mm:ss+HH:mm' * * @param timeZoneOffset * a string representing the time zone offset in hours and minutes, e.g., +02:00 * */ public static String toISO8601(int year, int month, int day, int hour, int minute, int second, String timeZoneOffset) { return toISO8601(true, year, month, day, hour, minute, second) + timeZoneOffset; } public static void main(String[] args) { String localTime = "2011-10-16T01:00:00+01:00"; System.out.println("localTime: " + localTime); System.out.println("converted to UTC: " + convertLocalToUTC(localTime) + "\n"); String utcTime = "2009-12-31 20:00:00"; System.out.println("UTC time: " + utcTime); String localOffset = "+05"; System.out.println("converted to local time at '" + localOffset + "' is: " + convertUTCToLocal(utcTime, localOffset)); } public static ITimePosition createTimePosition(Date startValue) { return (ITimePosition) TimeFactory.createTime(createISO8601TimeString(startValue, "+00:00")); } public static String createISO8601TimeString(Date startValue) { GregorianCalendar calendar = new GregorianCalendar(); calendar.setTime(startValue); // Problem: java.util.Date always sets the time zone to the // local time // zone, where the SOS is installed. // Hence, we have to make it UTC: int year = calendar.get(Calendar.YEAR); int month = calendar.get(Calendar.MONTH) + 1; int day = calendar.get(Calendar.DAY_OF_MONTH); int hour = calendar.get(Calendar.HOUR_OF_DAY); int minute = calendar.get(Calendar.MINUTE); int second = calendar.get(Calendar.SECOND); String startTimeAsISO8601 = TimeConverter.toISO8601(true, year, month, day, hour, minute, second); return startTimeAsISO8601; } public static String createISO8601TimeString(Date startValue, String timezoneOffset) { return createISO8601TimeString(startValue) + timezoneOffset; } /** * This helper method creates an {@link ITimePosition} from a * {@link java.util.Date} object (which is in the time zone of the SOS * server), and converts it to the requested time zone as defined in the * temporalFilter parameter. * * @param date * the time stamp of an observation but in the local time zone of * the SOS server. * @param temporalFilter * as accepted by the SOS server. * @return */ public static ITimePosition createTimeFromDate(Date date, String temporalFilter) { // Problem: java.util.Date always sets the time zone to the local time // zone, where the SOS is installed. // Hence, we have to make it UTC: String timeAsString = createISO8601TimeString(date); if (temporalFilter != null) { // if a temporalFilter was specified by the client, find out the // requested time zone, so that we can convert the UTC time to that // one: String queriedTimeZoneOffset; if (temporalFilter.contains("last:")) { queriedTimeZoneOffset = extractTemporalOperandAfterKeyWord(temporalFilter).split(",")[1]; } else { String queriedTimeAsISO8601 = extractTemporalOperandAfterKeyWord(temporalFilter); if (queriedTimeAsISO8601.contains(",")) { // time period has been requested; it's fine to only // consider // begin time to find out time zone: queriedTimeAsISO8601 = queriedTimeAsISO8601.split(",")[0]; } queriedTimeZoneOffset = TimeConverter.getTimeZoneOffset(queriedTimeAsISO8601); } // now, convert to the local time used in the query by the client: timeAsString = TimeConverter.convertUTCToLocal(timeAsString, queriedTimeZoneOffset); } ITimePosition time = new TimePosition(timeAsString); return time; } /** * @param temporalFilter * the temporalFilter as accepted by the SOS server, e.g., * 'equals:2010-12-31T15:00:00+02:00' * @return the String after the keyword, e.g., '2010-12-31T15:00:00+02:00'. */ public static String extractTemporalOperandAfterKeyWord(String temporalFilter) { if (temporalFilter.contains("equals:")) { return temporalFilter.substring(temporalFilter.indexOf("equals:") + 7); } else if (temporalFilter.contains("during:")) { return temporalFilter.substring(temporalFilter.indexOf("during:") + 7); } else if (temporalFilter.contains("after:")) { return temporalFilter.substring(temporalFilter.indexOf("after:") + 6); } else if (temporalFilter.contains("before:")) { return temporalFilter.substring(temporalFilter.indexOf("before:") + 7); } else if (temporalFilter.contains("last:")) { return temporalFilter.substring(temporalFilter.indexOf("last:") + 5); } else { throw new IllegalArgumentException("Error while parsing the temporal filter."); } } }