2015-11-02 2 views
3

Я пробовал использовать библиотеку <time.h>, но, похоже, <time.h> не поддерживает времена, ранее ранние, чем 1900, и, возможно, более чем на один год.Расчет разницы во времени в C

Мои вопросы здесь:

  1. Могу ли я использовать <time.h> вычислить разницу во времени (в секундах, часах или днях) между ними, например:

    1 мая 2744y и 24 января 566y

  2. <time.h> поддержка високосных годов? Смысл, если я вычислил разницу выше - будет ли это считать високосные годы? Я, очевидно, может сделать что-то вроде:

    int toDays(struct tm *date) 
    { 
        int days = date->tm_yday; 
        int year; 
        for (year = 1; year < date->tm_year; ++year) 
        { 
         days += isLeapYear(year) ? 366 : 365; 
        } 
        return days; 
    } 
    

Но потом опять - tm_year имп с 1900 года, я прав?

Если честно, у меня нет понимания этой структуры, и я, вероятно, буду писать ее самостоятельно, если кто-то не поможет мне в этом. Есть ли смысл использовать <time.h>, когда я хочу рассчитать годы, как в вопросе 1?

+1

Это зависит от вашего O/S и библиотеки, и «bittiness» из вашей машины. 32-разрядные системы могут иметь проблемы за пределами диапазона 1902..2037 (32-разрядные целые числа, основанные на 1970-01-01 00:00:00 +00: 00 в качестве эпохи). 64-разрядные системы часто имеют 64-разрядный тип 'time_t', а диапазон дат на них является очень большим (смерть шкалы универсума). Да, функции знают о високосных годах. Понимают ли они все капризы того, когда изменилась область мира от юлианского до григорианского календаря (если она действительно соблюдалась) - это отдельное обсуждение. Часовые пояса тоже сложны! –

+0

Возможный дубликат [Как распечатать временную разницу в точности миллисекунд и наносекунды?] (Http://stackoverflow.com/questions/16275444/how-to-print-time-difference-in-accuracy-of-milliseconds-and -nanoseconds) –

+0

@OlexandrKravchuk: Почему это как дубликат? Это целые секунды, а не миллисекунды или наносекунды, не так ли? –

ответ

1

Вы можете попробовать функцию difftime().

Сначала вы должны определить две структуры, которые могут содержать требуемые данные, например.

struct tm start_date, end_date; 

Затем заполните структуру данными в соответствии с вашей датой.

Затем используйте difftime() как

seconds = difftime(mktime(&end_date),mktime(&start_date)) 

Следующий пример поможет вам понять поток.

#include<stdio.h> 
#include<time.h> 
int main() 
{ 
    time_t now; 
    struct tm start_date, end_date; 
    start_date = *localtime(&now); 
    end_date = *localtime(&now); 

    start_date.tm_year = 1013; 
    end_date.tm_year = 1015; 

    unsigned long int diff = difftime(mktime(&end_date), mktime(&start_date)); 
    printf("DIFF: [%lu]",diff); 
    return(0); 
} 
1

Если у вас есть 64-разрядной системы, такие как Mac OS X (10,11 El Capitan используется), то это работает:

#include <inttypes.h> 
#include <stdio.h> 
#include <time.h> 

int main(void) 
{ 
    int y1 = 27440; 
    int m1 = 5; 
    int d1 = 1; 
    int y2 = 5660; 
    int m2 = 1; 
    int d2 = 24; 
    struct tm tm1 = { .tm_year = y1 - 1900, .tm_mon = m1 - 1, .tm_mday = d1 }; 
    struct tm tm2 = { .tm_year = y2 - 1900, .tm_mon = m2 - 1, .tm_mday = d2 }; 
    time_t t1 = mktime(&tm1); 
    time_t t2 = mktime(&tm2); 
    size_t dt = t1 - t2;  // Dodgy assignment…I get away with it, but… 

    char buffer[128]; 
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tm1); 
    printf("t1 = %20s\n", buffer); 
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tm2); 
    printf("t2 = %20s\n", buffer); 

    printf("t1 = %" PRIdMAX "\n", (intmax_t)t1); 
    printf("t2 = %" PRIdMAX "\n", (intmax_t)t2); 
    printf("dt = %zu seconds\n", dt); 
    printf("dt = %zu hours\n", dt/3600); 
    printf("dt = %zu days\n", dt/(24 * 3600)); 
    return 0; 
} 

Выход я получаю:

t1 = 27440-05-01 00:00:00 
t2 = 5660-01-24 00:00:00 
t1 = 803766009600 
t2 = 116447184000 
dt = 687318825600 seconds 
dt = 190921896 hours 
dt = 7955079 days 

Вещи не так уж хороши, пытаясь вернуться к ретроспективе. Разделив обе значения года на 10 выходов:

t1 = 2744-05-01 00:00:00 
t2 = 0566-01-24 00:00:00 
t1 = 24435504000 
t2 = -1 
dt = 24435504001 seconds 
dt = 6787640 hours 
dt = 282818 days 

Обратите внимание, что -1 указывает на ошибку; система не желает играть с датами в первом тысячелетии (что делает вычисления dt неточными). AFAICT, на Mac, mktime() не идет еще дальше во времени, чем могут идти 32-битные знаковые значения - он принимает 1902-01-01, но отклоняет 1901-01-01.Предел 32-бит:

-2147483647 = Fri Dec 13 12:45:53 1901 (US/Pacific) 

Код испытания:

static int test_year(int year) 
{ 
    struct tm tm1 = { .tm_year = year - 1900, .tm_mon = 0, .tm_mday = 1 }; 
    time_t t1 = mktime(&tm1); 
    return (t1 != -1); 
} 

static void early_year(void) 
{ 
    int y_lo = 566; 
    int y_hi = 1902; 
    assert(test_year(y_lo) == 0); 
    assert(test_year(y_hi) == 1); 

    while (y_lo != y_hi) 
    { 
     int y_md = (y_lo + y_hi)/2; 
     printf("lo = %4d; hi = %4d; md = %4d\n", y_lo, y_hi, y_md); 
     if (test_year(y_md) == 0) 
      y_lo = y_md + 1; 
     else 
      y_hi = y_md - 1; 
    } 
    printf("Valid back to %4d\n", y_lo); 
} 

Результат вызова этого кода:

lo = 566; hi = 1902; md = 1234 
lo = 1235; hi = 1902; md = 1568 
lo = 1569; hi = 1902; md = 1735 
lo = 1736; hi = 1902; md = 1819 
lo = 1820; hi = 1902; md = 1861 
lo = 1862; hi = 1902; md = 1882 
lo = 1883; hi = 1902; md = 1892 
lo = 1893; hi = 1902; md = 1897 
lo = 1898; hi = 1902; md = 1900 
lo = 1901; hi = 1902; md = 1901 
Valid back to 1902 

YMMV, как говорится; это будет зависеть от системы, над которой вы работаете. Обратите внимание, что чем дальше вы заходите вовремя, тем менее надежными являются часы и календари. Игнорируя такие тонкости, как 30 февраля 1712 года (в Швеции), вы получаете самые разные даты между 1584 и 20-м годами для дат, когда страны переключались с юлианского календаря на григорианский календарь (1752 год был датой перехода для Великобритании и ее колоний, например). Обычно люди применяют календарь «пролепит-григорианский» назад.

+0

С 'struct tm tm1 = {.tm_year = y1 - 1900, .tm_mon = m1 - 1, .tm_mday = d1}; ... time_t t1 = mktime (&tm1); ', инициализирует ли остальные поля 0 – chux

+0

@chux: yes - отсутствующие инициализаторы эквивалентны инициализаторам по умолчанию (фактически нулевым). –

+0

' difftime (t1, t2)/(24 * 60 * 60L) 'избегает« уродливого назначения ». – chux

0
  1. Диапазон данных time.h Функции работы варьируются между системами. Разумно предположить, что они работают в 1970-2037 годах. Многие системы работают в более широком диапазоне. OP, похоже, работает уже в 1900 году.

  2. Доминантный календар, используемый сегодня: григорианский начал 1582. Его принятие в мире варьируется. Таким образом, дата, подобная 24 января 566 года, нуждается в квалификации.

Пусть Op в time работает свыше 2000 до 2400 и все даты Gregorian, projected взад и вперед по мере необходимости:

Используйте «трюк», что 400 григорианские лет 400*365+97 дней (это кратна 7).

Так, чтобы получить количество дней с помощью функции OP, которая, надеюсь, работает в диапазоне 400 лет 2000-2400:

long long day_number(int year, int, month, int day) { 
    #define DaysPer400Year (400LL*365 + 97) 
    long long yearll = year - 2000LL; 
    year = yearll % 400; 
    int century400 = yearll/400; 
    if (year < 0) { 
    year += 400; 
    century400--; 
    } 
    long long number = century400 * DaysPer400Year; 
    number += OP_day_number(year + 2000, month, day); 
    return number; 
} 
Смежные вопросы