org.apache.falcon.util.DateUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.falcon.util.DateUtil.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.falcon.util;

import org.apache.commons.lang3.StringUtils;
import org.apache.falcon.FalconException;
import org.apache.falcon.entity.v0.SchemaHelper;
import org.apache.falcon.entity.v0.Frequency;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Helper to get date operations.
 */
public final class DateUtil {

    private static final long MINUTE_IN_MS = 60 * 1000L;
    private static final long HOUR_IN_MS = 60 * MINUTE_IN_MS;
    private static final long DAY_IN_MS = 24 * HOUR_IN_MS;
    private static final long MONTH_IN_MS = 31 * DAY_IN_MS;

    //Friday, April 16, 9999 7:12:55 AM UTC corresponding date
    public static final Date NEVER = new Date(Long.parseLong("253379862775000"));

    public static final long HOUR_IN_MILLIS = 60 * 60 * 1000;

    private static final Pattern GMT_OFFSET_COLON_PATTERN = Pattern.compile("^GMT(\\-|\\+)(\\d{2})(\\d{2})$");

    public static final TimeZone UTC = getTimeZone("UTC");

    public static final String ISO8601_UTC_MASK = "yyyy-MM-dd'T'HH:mm'Z'";
    private static String activeTimeMask = ISO8601_UTC_MASK;
    private static TimeZone activeTimeZone = UTC;

    private static final Pattern VALID_TIMEZONE_PATTERN = Pattern.compile("^UTC$|^GMT(\\+|\\-)\\d{4}$");

    private static final String ISO8601_TZ_MASK_WITHOUT_OFFSET = "yyyy-MM-dd'T'HH:mm";
    private static boolean entityInUTC = true;

    private DateUtil() {
    }

    /**
     * Configures the Datetime parsing with  process timezone.
     *
     */
    public static void setTimeZone(String tz) throws FalconException {
        if (StringUtils.isBlank(tz)) {
            tz = "UTC";
        }
        if (!VALID_TIMEZONE_PATTERN.matcher(tz).matches()) {
            throw new FalconException("Invalid entity timezone, it must be 'UTC' or 'GMT(+/-)####");
        }
        activeTimeZone = TimeZone.getTimeZone(tz);
        entityInUTC = activeTimeZone.equals(UTC);
        activeTimeMask = (entityInUTC) ? ISO8601_UTC_MASK : ISO8601_TZ_MASK_WITHOUT_OFFSET + tz.substring(3);
    }

    public static Date getNextMinute(Date time) {
        Calendar insCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
        insCal.setTime(time);
        insCal.add(Calendar.MINUTE, 1);
        return insCal.getTime();

    }

    public static String getDateFormatFromTime(long milliSeconds) {
        return SchemaHelper.getDateFormat().format((new Date(milliSeconds)));
    }

    /**
     * This function should not be used for scheduling related functions as it may cause correctness issues in those
     * scenarios.
     * @param frequency
     * @return
     */
    public static Long getFrequencyInMillis(Frequency frequency) {
        switch (frequency.getTimeUnit()) {

        case months:
            return MONTH_IN_MS * frequency.getFrequencyAsInt();

        case days:
            return DAY_IN_MS * frequency.getFrequencyAsInt();

        case hours:
            return HOUR_IN_MS * frequency.getFrequencyAsInt();

        case minutes:
            return MINUTE_IN_MS * frequency.getFrequencyAsInt();

        default:
            return null;
        }
    }

    /**
     * Returns the current time, with seconds and milliseconds reset to 0.
     * @return
     */
    public static Date now() {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     * Adds the supplied number of seconds to the given date and returns the new Date.
     * @param date
     * @param seconds
     * @return
     */
    public static Date offsetTime(Date date, int seconds) {
        return new Date(1000L * seconds + date.getTime());
    }

    /**
     * Parses a datetime in ISO8601 format in the  process timezone.
     *
     * @param s string with the datetime to parse.
     * @return the corresponding {@link java.util.Date} instance for the parsed date.
     * @throws java.text.ParseException thrown if the given string was
     * not an ISO8601 value for the  process timezone.
     */
    public static Date parseDateFalconTZ(String s) throws ParseException {
        s = s.trim();
        ParsePosition pos = new ParsePosition(0);
        Date d = getISO8601DateFormat(activeTimeZone, activeTimeMask).parse(s, pos);
        if (d == null) {
            throw new ParseException("Could not parse [" + s + "] using [" + activeTimeMask + "] mask",
                    pos.getErrorIndex());
        }
        if (s.length() > pos.getIndex()) {
            throw new ParseException("Correct datetime string is followed by invalid characters: " + s,
                    pos.getIndex());
        }
        return d;
    }

    private static DateFormat getISO8601DateFormat(TimeZone tz, String mask) {
        DateFormat dateFormat = new SimpleDateFormat(mask);
        // Stricter parsing to prevent dates such as 2011-12-50T01:00Z (December 50th) from matching
        dateFormat.setLenient(false);
        dateFormat.setTimeZone(tz);
        return dateFormat;
    }

    private static DateFormat getSpecificDateFormat(String format) {
        DateFormat dateFormat = new SimpleDateFormat(format);
        dateFormat.setTimeZone(activeTimeZone);
        return dateFormat;
    }

    /**
     * Formats a {@link java.util.Date} as a string using the specified format mask.
     * <p/>
     * The format mask must be a {@link java.text.SimpleDateFormat} valid format mask.
     *
     * @param d {@link java.util.Date} to format.
     * @return the string for the given date using the specified format mask,
     * <code>NULL</code> if the {@link java.util.Date} instance was <code>NULL</code>
     */
    public static String formatDateCustom(Date d, String format) {
        return (d != null) ? getSpecificDateFormat(format).format(d) : "NULL";
    }

    /**
     * Formats a {@link java.util.Date} as a string in ISO8601 format using process timezone.
     *
     * @param d {@link java.util.Date} to format.
     * @return the ISO8601 string for the given date, <code>NULL</code> if the {@link java.util.Date} instance was
     * <code>NULL</code>
     */
    public static String formatDateFalconTZ(Date d) {
        return (d != null) ? getISO8601DateFormat(activeTimeZone, activeTimeMask).format(d) : "NULL";
    }

    /**
     * Returns the {@link java.util.TimeZone} for the given timezone ID.
     *
     * @param tzId timezone ID.
     * @return  the {@link java.util.TimeZone} for the given timezone ID.
     */
    public static TimeZone getTimeZone(String tzId) {
        if (tzId == null) {
            throw new IllegalArgumentException("Timezone cannot be null");
        }
        tzId = handleGMTOffsetTZNames(tzId); // account for GMT-####
        TimeZone tz = TimeZone.getTimeZone(tzId);
        // If these are not equal, it means that the tzId is not valid (invalid tzId's return GMT)
        if (!tz.getID().equals(tzId)) {
            throw new IllegalArgumentException("Invalid TimeZone: " + tzId);
        }
        return tz;
    }

    /**
     * {@link java.util.TimeZone#getTimeZone(String)} takes the timezone ID as an argument; for invalid IDs
     * it returns the <code>GMT</code> TimeZone.  A timezone ID formatted like <code>GMT-####</code> is not a valid ID,
     * however, it will actually map this to the <code>GMT-##:##</code> TimeZone, instead of returning the
     * <code>GMT</code> TimeZone.  We check (later) check that a timezone ID is valid by calling
     * {@link java.util.TimeZone#getTimeZone(String)} and seeing if the returned
     * TimeZone ID is equal to the original; because we want to allow <code>GMT-####</code>, while still
     * disallowing actual invalid IDs, we have to manually replace <code>GMT-####</code>
     * with <code>GMT-##:##</code> first.
     *
     * @param tzId The timezone ID
     * @return If tzId matches <code>GMT-####</code>, then we return <code>GMT-##:##</code>; otherwise,
     * we return tzId unaltered
     */
    private static String handleGMTOffsetTZNames(String tzId) {
        Matcher m = GMT_OFFSET_COLON_PATTERN.matcher(tzId);
        if (m.matches() && m.groupCount() == 3) {
            tzId = "GMT" + m.group(1) + m.group(2) + ":" + m.group(3);
        }
        return tzId;
    }

    /**
     * Create a Calendar instance for UTC time zone using the specified date.
     * @param dateString
     * @return appropriate Calendar object
     * @throws Exception
     */
    public static Calendar getCalendar(String dateString) throws Exception {
        return getCalendar(dateString, activeTimeZone);
    }

    /**
     * Create a Calendar instance using the specified date and Time zone.
     * @param dateString
     * @param tz : TimeZone
     * @return appropriate Calendar object
     * @throws Exception
     */
    public static Calendar getCalendar(String dateString, TimeZone tz) throws Exception {
        Date date = DateUtil.parseDateFalconTZ(dateString);
        Calendar calDate = Calendar.getInstance();
        calDate.setTime(date);
        calDate.setTimeZone(tz);
        return calDate;
    }

    /**
     * Formats a {@link java.util.Calendar} as a string in ISO8601 format process timezone.
     *
     * @param c {@link java.util.Calendar} to format.
     * @return the ISO8601 string for the given date, <code>NULL</code> if the {@link java.util.Calendar} instance was
     * <code>NULL</code>
     */
    public static String formatDateFalconTZ(Calendar c) {
        return (c != null) ? formatDateFalconTZ(c.getTime()) : "NULL";
    }

}