21

整数として日付、つまり年、月、日があるとします。指定された日付が属する週のISO 8601 週番号を計算するための、適切な (正しい) 簡潔でかなり読みやすいアルゴリズムは何ですか? もっと良い方法があるに違いないと思わせる、本当に恐ろしいコードに出くわしました。

私はこれをJavaでやろうとしていますが、あらゆる種類のオブジェクト指向言語の疑似コードで問題ありません。

4

8 に答える 8

13

Calendar オブジェクトを使用して (FirstDayOfWeek を Monday に設定し、MinimalDaysInFirstWeek を 4 に設定して ISO 8601 に準拠させます)、get(Calendar.WEEK_OF_YEAR) を呼び出すことができると思います。

于 2008-09-29T01:29:37.400 に答える
12
/* Build a calendar suitable to extract ISO8601 week numbers
 * (see http://en.wikipedia.org/wiki/ISO_8601_week_number) */
Calendar calendar = Calendar.getInstance();
calendar.setMinimalDaysInFirstWeek(4);
calendar.setFirstDayOfWeek(Calendar.MONDAY);

/* Set date */
calendar.setTime(date);

/* Get ISO8601 week number */
calendar.get(Calendar.WEEK_OF_YEAR);
于 2013-11-25T17:32:55.210 に答える
8

joda-time ライブラリには ISO8601 カレンダーがあり、次の機能を提供します。

http://joda-time.sourceforge.net/cal_iso.html

yyyy-Www-dTHH:MM:SS.SSS ISO8601 のこの形式には、次のフィールドがあります。

* four digit weekyear, see rules below
* two digit week of year, from 01 to 53
* one digit day of week, from 1 to 7 where 1 is Monday and 7 is Sunday
* two digit hour, from 00 to 23
* two digit minute, from 00 to 59
* two digit second, from 00 to 59
* three decimal places for milliseconds if required

週は常に完全であり、年の最初の週はその年の最初の木曜日を含む週です。この定義は、年の最初の週が前年に始まり、最後の週が翌年に終わることを意味します。weekyear フィールドは、その週を所有する年を参照するように定義されており、実際の年とは異なる場合があります。

つまり、DateTime オブジェクトを作成し、getWeekOfWeekyear() というやや紛らわしい (しかし論理的には) という名前の関数を呼び出します。ここで、weekyear は、ISO8601 で使用される特定の週ベースの年の定義です。

一般的に、joda-time は非常に便利な API です。私は、それらを使用する API とのインターフェースが必要な場合を除いて、java.util.Calendar と java.util.Date を完全に使用するのをやめました。

于 2008-09-29T07:32:17.217 に答える
4

Java.util.Calendar だけでこのトリックを実行できます。Calendar インスタンスを作成し、週の最初の曜日 と最初の週の最小日数を設定できます。

Calendar calendar = Calendar.getInstance();
calendar.setMinimalDaysInFirstWeek(4);
calendar.setFirstDayOfWeek(Calendar.MONDAY);
calendar.setTime(date);

// Now you are ready to take the week of year.
calendar.get(Calendar.WEEK_OF_YEAR);

これはjavaDocによって提供されます。

getFirstDayOfWeek() が MONDAY で getMinimalDaysInFirstWeek() が 4 の場合、週の決定はISO 8601標準と互換性があります。これらの値は、標準が優先されるロケールで使用されます。これらの値は、setFirstDayOfWeek() および setMinimalDaysInFirstWeek() を呼び出して明示的に設定できます。

于 2016-02-03T15:28:37.917 に答える
2

Calendar クラスはほとんど機能しますが、ISO の週ベースの年は、"Olson's Timezone package" 準拠のシステムが報告するものと一致しません。次の Linux ボックスの例は、週ベースの年の値 (2009 年) が実際の年 (2010 年) とどのように異なるかを示しています。

$ TZ=UTC /usr/bin/date --date="2010-01-01 12:34:56" "+%a %b %d %T %Z  %%Y=%Y,%%G=%G  %%W=%W,%%V=%V  %s"
Fri Jan 01 12:34:56 UTC  %Y=2010,%G=2009  %W=00,%V=53  1262349296

しかし、Java の Calendar クラスはまだ 2010 年を報告しますが、年の週は正しいです。skaffman が言及したJoda -Time クラスは、これを正しく処理します。

import java.util.Calendar;
import java.util.TimeZone;
import org.joda.time.DateTime;

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
cal.setTimeInMillis(1262349296 * 1000L);
cal.setMinimalDaysInFirstWeek(4);
cal.setFirstDayOfWeek(Calendar.MONDAY);
System.out.println(cal.get(Calendar.WEEK_OF_YEAR));     // %V
System.out.println(cal.get(Calendar.YEAR));             // %G

DateTime dt = new DateTime(1262349296 * 1000L);
System.out.println(dt.getWeekOfWeekyear());             // %V
System.out.println(dt.getWeekyear());                   // %G

そのプログラムを実行すると、次のように表示されます。

53 2010 53 2009

したがって、ISO 8601 の週番号は Calendar から正しいですが、週ベースの年は正しくありません。

strftime(3) レポートの man ページ:

  %G     The ISO 8601 week-based year (see NOTES) with century as  a  decimal  number.   The
         4-digit year corresponding to the ISO week number (see %V).  This has the same for‐
         mat and value as %Y, except that if the ISO week number belongs to the previous  or
         next year, that year is used instead. (TZ)
于 2014-05-23T21:04:04.453 に答える
1

最先端に行きたい場合は、(Joda Fame の) Stephen Colebourne が率いるJSR-310 コードベース (Date Time API) の最新のドロップを利用できます。流暢なインターフェイスであり、効果的に Joda をボトムアップで再設計したものです。

于 2008-09-29T13:54:52.087 に答える
-2

これは逆です: 月曜日の日付を返します (perl)

use POSIX qw(mktime);
use Time::localtime;

sub monday_of_week {
    my $year=shift;
    my $week=shift;
    my $p_date=shift;

    my $seconds_1_jan=mktime(0,0,0,1,0,$year-1900,0,0,0);
    my $t1=localtime($seconds_1_jan);
    my $seconds_for_week;
    if (@$t1[6] < 5) {
#first of january is a thursday (or below)
        $seconds_for_week=$seconds_1_jan+3600*24*(7*($week-1)-@$t1[6]+1);
    } else {
        $seconds_for_week=$seconds_1_jan+3600*24*(7*($week-1)-@$t1[6]+8);
    }
    my $wt=localtime($seconds_for_week);
    $$p_date=sprintf("%02d/%02d/%04d",@$wt[3],@$wt[4]+1,@$wt[5]+1900);
}

于 2009-04-09T22:25:29.047 に答える