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

one.nio.util.Dates Maven / Gradle / Ivy

/*
 * Copyright 2020 Odnoklassniki Ltd, Mail.Ru Group
 *
 * 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 one.nio.util;

import java.util.TimeZone;

/**
 * Fast garbage-free algorithms for manipulating calendar dates
 */
public class Dates {
    public static final TimeZone TIME_ZONE = TimeZone.getDefault();

    public static final long JAN_1_1600 = -11676096000000L;
    public static final long MS_IN_DAY = 24 * 3600 * 1000;
    public static final int DAYS_IN_400_YEARS = 146097;
    public static final int DAYS_IN_4_YEARS = 1461;
    public static final int MONTH_AND_DAY_MASK = 0x1ff;
    public static final int FEB_29 = 2 << 5 | 29;

    // Map dayNum -> year|month|day
    private static final short[] CALENDAR = new short[DAYS_IN_4_YEARS];

    static {
        int dayNum = 0;
        for (int year = 0; year < 4; year++) {
            for (int month = 1; month <= 12; month++) {
                int days = daysInMonth(month, year);
                for (int day = 1; day <= days; day++) {
                    CALENDAR[dayNum++] = (short) (year << 9 | month << 5 | day);
                }
            }
        }
    }

    // Encode year|month|day into a single integer date
    public static int encode(int year, int month, int day) {
        return year << 9 | month << 5 | day;
    }

    public static int year(int date) {
        return date >> 9;
    }

    public static int month(int date) {
        return (date >>> 5) & 15;
    }

    public static int day(int date) {
        return date & 31;
    }

    public static boolean isLeapYear(int year) {
        return (year & 3) == 0 && (year % 100 != 0 || year % 400 == 0);
    }

    public static int daysInMonth(int month, int year) {
        return month == 2 ? (isLeapYear(year) ? 29 : 28) : 30 + ((0b1010110101010 >>> month) & 1);
    }

    // Translate UTC timestamp to local time zone
    public static long asLocal(long millis) {
        return millis + TIME_ZONE.getOffset(millis);
    }

    // Number of days since Jan 1, 1600
    public static int dayNum(long millis) {
        return (int) ((millis - JAN_1_1600) / MS_IN_DAY);
    }

    // Parse timestamp into year|month|day
    public static int dateOfMillis(long millis) {
        int dayNum = dayNum(millis);
        int y400 = dayNum / DAYS_IN_400_YEARS;
        dayNum %= DAYS_IN_400_YEARS;
        dayNum += (dayNum - 60) / 36524;
        int y4 = dayNum / DAYS_IN_4_YEARS;
        return ((y400 * 400 + y4 * 4 + 1600) << 9) + CALENDAR[dayNum % DAYS_IN_4_YEARS];
    }

    // Number of full years between two timestamps. Positive when fromMillis < toMillis
    public static int yearsBetween(long fromMillis, long toMillis) {
        int fromDate = dateOfMillis(fromMillis);
        int toDate = dateOfMillis(toMillis);
        if ((fromDate & MONTH_AND_DAY_MASK) == FEB_29 && !isLeapYear(toDate >> 9)) {
            fromDate--;
        }
        return (toDate - fromDate) >> 9;
    }

    // Number of days between two timestamps. Positive when fromMillis < toMillis
    public static int daysBetween(long fromMillis, long toMillis) {
        return dayNum(toMillis) - dayNum(fromMillis);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy