最近競技プログラミングというものにはまっていていろいろな関数を用意しておいた方が便利だなと言うことで時間関係のライブラリを作ってみた。 PHPとかなら組み込み関数で用意されているので楽なのだけど... あ、あの問題はPHPで解いたら楽だったか...

自分で作ってみて分かったのだが、時刻をUNIX timeに変換とか閏年を入れるとかなりめんどくさい。

最初UNIX timeにしていたのだけど問題の入力範囲が1970~とは限らないので0年~に変更。 UNIX timeにしたい人は適当に補正して下さい。

int sdlab_count_days(int year){
  int ret;
  if(year < 0 ){
    return - sdlab_count_days(- year) -366 + 365;
  }else if(year == 0){
    return 0;
  }

  ret = year * 365;
  ret += year / 4;
  ret -= year / 100;
  ret += year / 400;

  return ret;
}

uint64_t sdlab_get_ut(int year,int month,int date,
                        int hour,int minute,int second) {
  int month_days[13]={0, 31, 59, 90, 120, 151, 181,
                      212, 243, 273, 304, 334, 365};
  uint64_t ret;

  if(month < 1 || month > 12){
    return 0;
  }

  ret = sdlab_count_days(year - 1);
  ret *= 24 * 60 * 60;
  ret += month_days[month - 1] * 24 * 60 * 60;
  if(year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)){
    if(month >= 3){
      ret += 24 * 60 * 60;
    }
  }

  ret += (date - 1) * 24 * 60 * 60;
  ret += hour * 60 * 60;
  ret += minute * 60;
  ret += second;

  return ret;
}

int sdlab_count_leaps(int year) {
  int ret;

  if(year == 0){
    return 0;
  }

  ret = year / 4;
  ret -= year / 100;
  ret += year / 400;

  return ret;
}

bool sdlab_is_leap(int year) {
  if(year % 400 == 0 ||
     (year % 4 == 0 && year % 100 !=0)){
    return true;
  }

  return false;
}

int sdlab_get_hour(uint64_t ut)
{
  int month_days[13]={0, 31, 59, 90, 120, 151, 181,
                      212, 243, 273, 304, 334, 365};

  int day = ut / (24 * 60 * 60);
  int sec = ut % (24 * 60 * 60);
  int year = day / 365 + 1;
  int rest_days = day % 365;

  rest_days -= sdlab_count_leaps(year - 1);

  while(1){
    if((rest_days >= 0 && rest_days < 365) ||
       (rest_days == 365 && sdlab_is_leap(year))){
      break;
    }

    if(rest_days < 0){
      int tmp = -1 * rest_days / 365 + 1;
      rest_days += tmp * 365;
      rest_days += sdlab_count_leaps(year - 1) -
        sdlab_count_leaps(year - tmp - 1);
      year -= tmp;
    }else if(rest_days >= 365){
      int tmp = rest_days / 365;
      rest_days = rest_days % 365;
      rest_days -= sdlab_count_leaps(year + tmp - 1) -
        sdlab_count_leaps(year - 1);
      year += tmp;
    }else{
      break;
    }
  }

  if(sdlab_is_leap(year)){
    for(int i = 2; i <= 12; i++){
      month_days[i]++;
    }
  }

  for(int i = 1; i <= 12; i++) {
    if(rest_days >= month_days[i-1] && rest_days < month_days[i]){
      break;
    }
  }

  return sec / 3600;
}

int sdlab_get_min(uint64_t ut)
{
  int month_days[13]={0, 31, 59, 90, 120, 151, 181,
                      212, 243, 273, 304, 334, 365};

  int day = ut / (24 * 60 * 60);
  int sec = ut % (24 * 60 * 60);
  int year = day / 365 + 1;
  int rest_days = day % 365;

  rest_days -= sdlab_count_leaps(year - 1);

  while(1){
    if((rest_days >= 0 && rest_days < 365) ||
       (rest_days == 365 && sdlab_is_leap(year))){
      break;
    }

    if(rest_days < 0){
      int tmp = -1 * rest_days / 365 + 1;
      rest_days += tmp * 365;
      rest_days += sdlab_count_leaps(year - 1) -
        sdlab_count_leaps(year - tmp - 1);
      year -= tmp;
    }else if(rest_days >= 365){
      int tmp = rest_days / 365;
      rest_days = rest_days % 365;
      rest_days -= sdlab_count_leaps(year + tmp - 1) -
        sdlab_count_leaps(year - 1);
      year += tmp;
    }else{
      break;
    }
  }

  if(sdlab_is_leap(year)){
    for(int i = 2; i <= 12; i++){
      month_days[i]++;
    }
  }

  for(int i = 1; i <= 12; i++) {
    if(rest_days >= month_days[i-1] && rest_days < month_days[i]){
      break;
    }
  }

  return (sec / 60) % 60;
}

int sdlab_get_sec(uint64_t ut)
{
  int month_days[13]={0, 31, 59, 90, 120, 151, 181,
                      212, 243, 273, 304, 334, 365};

  int day = ut / (24 * 60 * 60);
  int sec = ut % (24 * 60 * 60);
  int year = day / 365 + 1;
  int rest_days = day % 365;

  rest_days -= sdlab_count_leaps(year - 1);

  while(1){
    if((rest_days >= 0 && rest_days < 365) ||
       (rest_days == 365 && sdlab_is_leap(year))){
      break;
    }

    if(rest_days < 0){
      int tmp = -1 * rest_days / 365 + 1;
      rest_days += tmp * 365;
      rest_days += sdlab_count_leaps(year - 1) -
        sdlab_count_leaps(year - tmp - 1);
      year -= tmp;
    }else if(rest_days >= 365){
      int tmp = rest_days / 365;
      rest_days = rest_days % 365;
      rest_days -= sdlab_count_leaps(year + tmp - 1) -
        sdlab_count_leaps(year - 1);
      year += tmp;
    }else{
      break;
    }
  }

  if(sdlab_is_leap(year)){
    for(int i = 2; i <= 12; i++){
      month_days[i]++;
    }
  }

  for(int i = 1; i <= 12; i++) {
    if(rest_days >= month_days[i-1] && rest_days < month_days[i]){
      break;
    }
  }

  return sec % 60;
}

int sdlab_get_year(uint64_t ut)
{
  int month_days[13]={0, 31, 59, 90, 120, 151, 181,
                      212, 243, 273, 304, 334, 365};

  int day = ut / (24 * 60 * 60);
  int sec = ut % (24 * 60 * 60);
  int year = day / 365 + 1;
  int rest_days = day % 365;

  rest_days -= sdlab_count_leaps(year - 1);

  while(1){
    if((rest_days >= 0 && rest_days < 365) ||
       (rest_days == 365 && sdlab_is_leap(year))){
      break;
    }

    if(rest_days < 0){
      int tmp = -1 * rest_days / 365 + 1;
      rest_days += tmp * 365;
      rest_days += sdlab_count_leaps(year - 1) -
        sdlab_count_leaps(year - tmp - 1);
      year -= tmp;
    }else if(rest_days >= 365){
      int tmp = rest_days / 365;
      rest_days = rest_days % 365;
      rest_days -= sdlab_count_leaps(year + tmp - 1) -
        sdlab_count_leaps(year - 1);
      year += tmp;
    }else{
      break;
    }
  }

  if(sdlab_is_leap(year)){
    for(int i = 2; i <= 12; i++){
      month_days[i]++;
    }
  }

  for(int i = 1; i <= 12; i++) {
    if(rest_days >= month_days[i-1] && rest_days < month_days[i]){
      break;
    }
  }

  return year;
}

int sdlab_get_day(uint64_t ut)
{
  int month_days[13]={0, 31, 59, 90, 120, 151, 181,
                      212, 243, 273, 304, 334, 365};

  int day = ut / (24 * 60 * 60);
  int sec = ut % (24 * 60 * 60);
  int year = day / 365 + 1;
  int rest_days = day % 365;

  rest_days -= sdlab_count_leaps(year - 1);

  while(1){
    if((rest_days >= 0 && rest_days < 365) ||
       (rest_days == 365 && sdlab_is_leap(year))){
      break;
    }

    if(rest_days < 0){
      int tmp = -1 * rest_days / 365 + 1;
      rest_days += tmp * 365;
      rest_days += sdlab_count_leaps(year - 1) -
        sdlab_count_leaps(year - tmp - 1);
      year -= tmp;
    }else if(rest_days >= 365){
      int tmp = rest_days / 365;
      rest_days = rest_days % 365;
      rest_days -= sdlab_count_leaps(year + tmp - 1) -
        sdlab_count_leaps(year - 1);
      year += tmp;
    }else{
      break;
    }
  }

  if(sdlab_is_leap(year)){
    for(int i = 2; i <= 12; i++){
      month_days[i]++;
    }
  }

  int i;
  for(i = 1; i <= 12; i++) {
    if(rest_days >= month_days[i - 1] && rest_days < month_days[i]){
      break;
    }
  }

  rest_days -= month_days[i - 1];

  return rest_days + 1;
}

int sdlab_get_month(uint64_t ut)
{
  int month_days[13]={0, 31, 59, 90, 120, 151, 181,
                      212, 243, 273, 304, 334, 365};

  int day = ut / (24 * 60 * 60);
  int sec = ut % (24 * 60 * 60);
  int year = day / 365 + 1;
  int rest_days = day % 365;

  rest_days -= sdlab_count_leaps(year - 1);

  while(1){
    if((rest_days >= 0 && rest_days < 365) ||
       (rest_days == 365 && sdlab_is_leap(year))){
      break;
    }

    if(rest_days < 0){
      int tmp = -1 * rest_days / 365 + 1;
      rest_days += tmp * 365;
      rest_days += sdlab_count_leaps(year - 1) -
        sdlab_count_leaps(year - tmp - 1);
      year -= tmp;
    }else if(rest_days >= 365){
      int tmp = rest_days / 365;
      rest_days = rest_days % 365;
      rest_days -= sdlab_count_leaps(year + tmp - 1) -
        sdlab_count_leaps(year - 1);
      year += tmp;
    }else{
      break;
    }
  }

  if(sdlab_is_leap(year)){
    for(int i = 2; i <= 12; i++){
      month_days[i]++;
    }
  }

  int i;
  for(i = 1; i <= 12; i++) {
    if(rest_days >= month_days[i-1] && rest_days < month_days[i]){
      break;
    }
  }

  return i;
}

  添付編集
Last-modified: 2015-08-09 (日) 12:41:05 (686d)