繁体   English   中英

Java如何在不使用外部库的情况下从毫秒获取月份

[英]Java How to get Month from milliseconds WITHOUT using external Libraries

我使用System.currentTimeMillis()来获得自1970年以来的毫秒数,我能够获得当前的小时,分​​钟,秒和年。 例如,我使用以下公式获得年份,并返回2015年:

          ((((currTimeInMilliSec / 1000) / 3600) / 24) / 365) + 1970

但是我如何计算月份,从毫秒开始计算闰年和不同月份的不同天数,如28,29,30,31。

注意:由于某种原因,我只需要使用currentTimeMillis函数来计算,我不想使用其他函数或外部库。 此外,我已经通过相关的帖子,但没有找到确切的答案。

使用GregorianCalendar。

GregorianCalendar c = new GregorianCalendar();

c.setTimeInMillis(1l);

int month = c.get(Calendar.MONTH);

这将返回0,即1月。 想象一下一年中有12个月的阵列。

是的,这是可能的。

有天文算法可以实现朱利安日数和日期时间戳之间的数字转换。 我熟悉的算法由J. Meeus在他的Astronomical Algorithms,2nd Ed。中发表。 该算法将朱利安日数转换为表示相应的整数向量:

  • MONTH_IN_YEAR(1-12)
  • DAY_IN_MONTH(1-28,29,30,31)
  • HOUR_IN_DAY(0-23)
  • MINUTE_IN_HOUR(0-59)
  • SECOND_IN_MINUTE(0-59)
  • MILLISECOND_IN_SECOND(0-999)

因为POSIX时间和Julian日数都是日期序列(连续时间单位的数量),所以它们互相转换是微不足道的。 因此,使用该算法的第一步是将POSIX时间(自1970年1月1日午夜以来的毫秒)转换为朱利安日数(自公元前4714年11月24日起,在公历中的公历)。 这很简单,因为您只需将毫秒转换为几天并调整时期。

以下是常量:

/** Accessor index for year field from a date/time vector of ints. */
public static final int YEAR = 0;

/** Accessor index for month-in-year field from a date/time vector of ints */
public static final int MONTH = 1;

/** Accessor index for day-in-month field from a date/time vector of ints */
public static final int DAY = 2;

/** Accessor index for hour-in-day field from a date/time vector of ints */
public static final int HOURS = 3;

/** Accessor index for minute-in-hour field from a date/time vector of ints */
public static final int MINUTES = 4;

/** Accessor index for second-in-minute field from a date/time vector of ints */
public static final int SECONDS = 5;

/** Accessor index for millis-in-second field from a date/time vector of ints */
public static final int MILLIS = 6;

/** The POSIX Epoch represented as a modified Julian Day number */
public static final double POSIX_EPOCH_AS_MJD = 40587.0d;

以下是将Julian Day Number(作为double )转换为整数向量的算法。 在下面的代码中,您可以将trunc()函数替换为Math.floor()并保留正确的行为:

public static int[] toVectorFromDayNumber(double julianDay) {

    int[] ymd_hmsm = {YEAR, MONTH, DAY, HOURS, MINUTES, SECONDS, MILLIS};
    int a, b, c, d, e, z;
    double f, x;

    double jd = julianDay + 0.5;

    z = (int) trunc(jd);
    f = (jd - z) + (0.5 / (86400.0 * 1000.0));

    if (z >= 2299161) {
        int alpha = (int) trunc((z - 1867216.25) / 36524.25);
        a = z + 1 + alpha - (alpha / 4);
    } else {
        a = z;
    }

    b = a + 1524;
    c = (int) trunc((b - 122.1) / 365.25);
    d = (int) trunc(365.25 * c);
    e = (int) trunc((b - d) / 30.6001);

    ymd_hmsm[DAY] = b - d - (int) trunc(30.6001 * e);
    ymd_hmsm[MONTH] = (e < 14) 
            ? (e - 1) 
            : (e - 13);
    ymd_hmsm[YEAR] = (ymd_hmsm[MONTH] > 2) 
            ? (c - 4716) 
            : (c - 4715);

    for (int i = HOURS; i <= MILLIS; i++) {
        switch (i) {
            case HOURS:
                f = f * 24.0;
                break;
            case MINUTES:  case SECONDS:
                f = f * 60.0;
                break;
            case MILLIS:
                f = f * 1000.0;
                break;
        }
        x = trunc(f);
        ymd_hmsm[i] = (int) x;
        f = f - x;
    }
    return ymd_hmsm;
}

例如,如果使用Julian Day Number 2457272.5调用该函数,它将返回以UTC表示午夜,2015年9月7日(劳动节)的以下整数向量:

[2015,9,7,0,0,0,0]

编辑:关于Meeus算法的一个值得注意的事情是它正确地解释了闰年和世纪日(包括世纪日例外)。 它仅使用整数和浮点运算,并且很可能比需要Java日历或日期时间API的对象实例化的解决方案更具性能。

我的变种:

public class Main  {

    public static class MyDate {
        int month;
        int day;

        public MyDate(int month, int day) {
            this.month = month;
            this.day = day;
        }
    }

    public static final int[] daysInMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    public static void main(String[] args) {
        long millis = System.currentTimeMillis();
        long days = millis / 86400000;
        long millisToday = millis % 86400000;
        int yearsPassedApprox = (int) days / 365;
        int daysPassedThisYear = (int) (days - (yearsPassedApprox * 365 + leapYearsCount(yearsPassedApprox)));
        int year = yearsPassedApprox + 1970;
        MyDate myDate = getMonthAndDay(year, daysPassedThisYear);
        int hours = (int) (millisToday / 3600000);
        int minutes = (int) ((millisToday % 3600000) / 60000);
        int seconds = (int) ((millisToday % 60000) / 1000);


        System.out.println("Year: " + year);
        System.out.println("Month: " + myDate.month);
        System.out.println("Day: " + myDate.day);
        System.out.println("Hour: " + hours);
        System.out.println("Minutes: " + minutes);
        System.out.println("Seconds: " + seconds);
    }

    public static MyDate getMonthAndDay(int year, int daysPassedThisYear) {
        int i;
        int daysLeft = daysPassedThisYear;
        boolean leapYear = isLeapYear(year);
        for (i = 0; i < daysInMonth.length; i++) {
            int days = daysInMonth[i];
            if (leapYear && i == 1) {
                days++;
            }
            if (days <= daysLeft) {
                daysLeft -= days;
            } else {
                break;
            }
        }
        return new MyDate(i + 1, daysLeft + 1);
    }

    public static int leapYearsCount(long yearsPassed) {
        int count = 0;
        for (int i = 1970; i < 1970 + yearsPassed ; i++) {
            if (isLeapYear(i)) {
                count++;
            }
        }
        return count;
    }

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

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM