Как реализовать подпрограмму преобразования метки времени эпохи без использования какой-либо библиотеки / пакета? - PullRequest
1 голос
/ 08 мая 2020

Я использую процедуру преобразования метки времени эпохи в год, месяц, день, часы, минуты и секунды.

Важное примечание: я не могу использовать какие-либо из существующих Java библиотек потому что эта процедура используется как тестовая программа, которая позже будет реализована в графическом процессоре. Поэтому не предлагайте использовать Localdate, ZonedDateTime, Datetime и т. Д. c. Подпрограмма должна использовать простые типы данных и c арифметические c операции.

Это спецификации:

  1. Входные данные - UNIX Epoch timestamp in seconds.
  2. Выходные данные представляют собой строку с year/month/day hour:minute.
  3. Дата и время ограничены от January 1st 1990 до January 1st 2050.
  4. No leap seconds в качестве входных данных UNIX временные метки эпох.

Подпрограммой обрабатываются только действительные временные метки эпохи, основанные на этих условиях.

Это то, что я пробовал, и я включаю его как реплицируемый Java программа.

У меня есть действующая процедура, которая работает для дат после 1 января 2000 года: процедура epochToDatetimeBase2000.

Я пытаюсь закодировать модуль, который будет работать с датами выше 1 января 1990 года, подпрограмма epochToDatetimeBase1990, которая не работает.

Это полный воспроизводимый исходный код программы, включающий как процедуры, так и тестовые данные:

public class MyClass {

    public static String epochToDatetimeBase2000(int epoch) {

        int epochOriginal = epoch;

        epoch = epoch - 946684800;      //  946684800 is Epoch for Saturday, 1 January 2000 00:00:00

        int[] days = new int[]{
            0,  31,  60,  91, 121, 152, 182, 213, 244, 274, 305, 335,
            366, 397, 425, 456, 486, 517, 547, 578, 609, 639, 670, 700,
            731, 762, 790, 821, 851, 882, 912, 943, 974,1004,1035,1065,
            1096,1127,1155,1186,1216,1247,1277,1308,1339,1369,1400,1430
        };        

        int second = epoch % 60;
        epoch = epoch / 60;
        int minute = epoch % 60;
        epoch = epoch / 60;
        int hour   = epoch % 24;
        epoch = epoch / 24;

        int years = epoch/(365*4+1)*4; 
        epoch %= 365*4+1;

        int year;
        for (year=3; year>0; year=year-1)
        {   
            if (epoch >= days[year*12])
                break;
        }

        int month;
        for (month=11; month>0; month--)
        {
            if (epoch >= days[year*12 + month])
                break;
        }

        int yearVal = years+year;
        int monthVal = month+1;
        int dayVal = epoch-days[year*12 + month]+1;

        String strDatetime = String.format("%d %02d/%02d/%02d %02d:%02d.%02d", epochOriginal, dayVal, monthVal, 2000+yearVal, hour, minute, second); // Float value.

        return strDatetime;

    }

    public static String epochToDatetimeBase1990(int epoch) {

        int epochOriginal = epoch;

        epoch = epoch - 631152000;      // 631152000 is Epoch for Monday, 1 January 1990 00:00:00

        int[] days = new int[]{
            0,  31,  60,  91, 121, 152, 182, 213, 244, 274, 305, 335,
            366, 397, 425, 456, 486, 517, 547, 578, 609, 639, 670, 700,
            731, 762, 790, 821, 851, 882, 912, 943, 974,1004,1035,1065,
            1096,1127,1155,1186,1216,1247,1277,1308,1339,1369,1400,1430
        };        

        int second = epoch % 60;
        epoch = epoch / 60;
        int minute = epoch % 60;
        epoch = epoch / 60;
        int hour   = epoch % 24;
        epoch = epoch / 24;

        int years = epoch/(365*4+1)*4; 
        epoch %= 365*4+1;

        int year;
        for (year=3; year>0; year=year-1)
        {   
            if (epoch >= days[year*12])
                break;
        }

        int month;
        for (month=11; month>0; month--)
        {
            if (epoch >= days[year*12 + month])
                break;
        }

        int yearVal = years+year;
        int monthVal = month+1;
        int dayVal = epoch-days[year*12 + month]+1;

        String strDatetime = String.format("%d %02d/%02d/%02d %02d:%02d.%02d", epochOriginal, dayVal, monthVal, 1990+yearVal, hour, minute, second); // Float value.

        return strDatetime;

    }

    public static void main(String args[]) {

        // USING BASE 2000
        System.out.println(epochToDatetimeBase2000(978307200));     // Epoch timestamp: 978307200       Date and time (GMT): Monday, 1 January 2001 00:00:00
        System.out.println(epochToDatetimeBase2000(631152000));     // Epoch timestamp: 631152000       Date and time (GMT): Tuesday, 1 January 1990 00:00:00
        System.out.println(epochToDatetimeBase2000(662688000));     // Epoch timestamp: 662688000       Date and time (GMT): Tuesday, 1 January 1991 00:00:00

        // USING BASE 1990
        System.out.println(epochToDatetimeBase1990(978307200));     // Epoch timestamp: 978307200       Date and time (GMT): Monday, 1 January 2001 00:00:00
        System.out.println(epochToDatetimeBase1990(631152000));     // Epoch timestamp: 631152000       Date and time (GMT): Tuesday, 1 January 1990 00:00:00
        System.out.println(epochToDatetimeBase1990(662688000));     // Epoch timestamp: 662688000       Date and time (GMT): Tuesday, 1 January 1991 00:00:00


    }


}

Это результат:

978307200 01/01/2001 00:00.00
631152000 -729/01/1992 00:00.00
662688000 -364/01/1992 00:00.00

978307200 01/01/2001 00:00.00
631152000 01/01/1990 00:00.00
662688000 31/12/1990 00:00.00     <- SHALL BE  1 January 1991 00:00:00

Ответы [ 2 ]

2 голосов
/ 08 мая 2020

Может быть, в вашем массиве days есть ошибка для epochToDatetimeBase1990? Я заметил, что значения точно такие же, как в epochToDatetimeBase2000. 2000 год - високосный, а 1990 не ! Таким образом, високосные годы начинаются в разных местах массива. Я думаю, что days должно быть определено как это в epochToDatetimeBase1990:

int[] days = new int[]{
    // 1990 is NOT a leap year
    0,  31,  59,  90, 120, 151, 181, 212, 243, 273, 304, 334,
    365, 396, 424, 455, 485, 516, 546, 577, 608, 638, 669, 699,

    // 1992 is a leap year here
    730, 761, 790, 821, 851, 882, 912, 943, 974,1004,1035,1065,
    1096,1127,1155,1186,1216,1247,1277,1308,1339,1369,1400,1430
};
1 голос
/ 08 мая 2020

Я приготовил другое решение. Пожалуйста, посмотрите.

Также это полезно для любых других границ лет, для этого просто измените START_YEAR, START_EPOCH и END_YEAR.

final static int START_YEAR = 1990;
final static long START_EPOCH = 631152000;
final static int END_YEAR = 2050;
final static int[] MONTH_DAYS = new int[]{31,28,31,30,31,30,31,31,30,31,30,31};

private static void convertEpochToDateTime(long epoch){
    long relativeEpoch = epoch-START_EPOCH;

    int[] daysAndRemainingSeconds = getTotalDaysAndRemainingSeconds(relativeEpoch);
    int remainingSeconds = daysAndRemainingSeconds[1];
    int[] time = convertSecondsToTime(remainingSeconds);

    int totalDays = daysAndRemainingSeconds[0];
    int[] yearAndRemainingDays = getYearAndRemainingDays(totalDays);
    int year = yearAndRemainingDays[0];
    int remainingDays = yearAndRemainingDays[1];

    int[] monthAndDays =getMonthsAndRemaingDays(remainingDays,isLeapYear(year));

    String strDatetime = String.format("%d %02d/%02d/%02d %02d:%02d.%02d", epoch, monthAndDays[1]+1, monthAndDays[0], year, time[0], time[1], time[2]);
    System.out.println(String.valueOf(strDatetime));
}

private static int[] getTotalDaysAndRemainingSeconds(long seconds){
    return new int[]{(int)seconds/86400,(int)seconds%86400};
}

private static int[] getYearAndRemainingDays(int days){
    int tmpDays = 0;
    for(int year=START_YEAR;year<=END_YEAR;year++){
        int daysInYear = isLeapYear(year)?366:365;
        if(tmpDays+daysInYear>days) return new int[]{year,days-tmpDays};
        tmpDays +=daysInYear;
    }
    return new int[]{0,0};
}

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

private static int[] convertSecondsToTime(int seconds){
    int sec = seconds % 60;
    int hr = seconds / 60;
    int min = hr % 60;
    hr = hr / 60;
    return new int[]{hr,min,sec};
}

private static int[] getMonthsAndRemaingDays(int days,boolean leapYear){
    int tmdDays = 0;
    for(int month=1;month<=12;month++){
        int daysInThisMonth = MONTH_DAYS[month-1]+(month==2 && leapYear?1:0);
        if(tmdDays+daysInThisMonth>days) return new int[]{month,days-tmdDays};
        tmdDays+=daysInThisMonth;
    }
    return new int[]{12,0};
}
...