実装
まずは、今回作った Objective-C による実装から示す。関数の機能は単純で、RFC3399 形式で表現された日時を元に NSDate
のオブジェクトを生成する。関数内で NSDate
オブジェクトを alloc
しているが、返す前に autorelease
しているため、荻原(2.0)本 (p.96) で言う「一時的なオブジェクト」となっている。また、関数を呼び出す側で自動解放プールを用意する必要がある。通常の Cocoa アプリの場合は、NSApplication
がイベントループの管理とともに自動解放プールも用意してくれる(→ 「荻原(2.0)本」p.98)。
この実装では NSString の機能のうち、以下のメソッドを多用している。
- - (NSRange)rangeOfCharacterFromSet:(NSCharacterSet*)aSet
aSet
で渡された文字集合中の文字が最初に見つかった場所を返す。- - (NSString*)substringToIndex:(NSUInteger)aIndex
- 先頭から位置
aIndex
までの部分文字列を返す。 - - (NSString*)substringWithRange:(NSRange)aRange
aRange.location
を開始位置とし、aRange.length
を長さとする部分文字列を返す。- - (NSString*)substringFromIndex:(NSUInteger)
aIndex
を開始位置としする末尾までの部分文字列を返す。
上記の substring...
の戻り値はいずれも一時的なオブジェクトになっている。
参照仕様
GData API の Protocl Reference によれば、各種日付には RFC3339 フォーマットが使われる、とある。これは GData API が使うデータフォーマット(Atom 形式; RFC 4287 で定義されている)の仕様によるものだ。
(「RFC 4287」より)
A Date construct is an element whose content MUST conform to the "date-time" production in [RFC3339]. In addition, an uppercase "T" character MUST be used to separate date and time, and an uppercase "Z" character MUST be present in the absence of a numeric time zone offset.[...snip...]
Example Date constructs:
<updated>2003-12-13T18:30:02Z</updated>
<updated>2003-12-13T18:30:02.25Z</updated>
<updated>2003-12-13T18:30:02+01:00</updated>
<updated>2003-12-13T18:30:02.25+01:00</updated>
上記の中で例として挙げられている 4 つのパターンを見れば書式のおよそは理解できる。
より詳細な 書式の定義は RFC 3339 にある。
date-fullyear = 4DIGIT date-month = 2DIGIT ; 01-12 date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on ; month/year time-hour = 2DIGIT ; 00-23 time-minute = 2DIGIT ; 00-59 time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second ; rules time-secfrac = "." 1*DIGIT time-numoffset = ("+" / "-") time-hour ":" time-minute time-offset = "Z" / time-numoffset partial-time = time-hour ":" time-minute ":" time-second [time-secfrac] full-date = date-fullyear "-" date-month "-" date-mday full-time = partial-time time-offset date-time = full-date "T" full-time
この定義から、日時の表現は「日付」と「時刻」に二分され、その区切りが文字「T」であること、また「時刻」は「時刻本体」と「時差」に分かれることが読みとれる。
「時差」については、時刻による差分で表現したもの(「+09:00」や「-5:00」など)か、あるいは文字「Z」を用いる(時差として文字「Z」を指定した場合、その時刻は UTC を意味する)。
さらに「時刻本体」の表現については、「時」「分」「秒」をそれぞれ 2 桁の十進数で表現する(1 桁の場合は先頭に「0」を付加する)。また「秒」については 1 秒以下を小数表現で「秒」に付けても良い、となっている。
GData API での時刻の取扱い
実際に GData API が返すフィードを見ると、updated
要素等は以下のようになっていて、確かに上記の書式に従っていることがわかる。
<published>2010-10-03T21:18:00.000+09:00</published> <updated>2010-10-03T21:18:00.840+09:00</updated>
一方、GData Objective-C Library が返す時刻データは GDataDateTime
クラスのインスタンスになっていて、そこから文字列データを取り出すと RFC3339 フォーマットの文字列となる。ただし、それを作る部分は以下のようになっているため、「秒数」の小数点以下が無視されている(GData Objective-C Client ver. 1.10.0)。これは、Cocoa の NSDateComponents が小数点以下の秒数をサポートしていないことによるものだと思われる(以下のコード中の dateComponents
は NSDateComponents のインスタンスを保持している)。
- (NSString *)stringValue { return [self RFC3339String]; } - (NSString *)RFC3339String { NSDateComponents *dateComponents = [self dateComponents]; NSInteger offset = [self offsetSeconds]; NSString *timeString = @""; // timeString like "T15:10:46-08:00" if ([self hasTime]) { NSString *timeOffsetString; // timeOffsetString like "-08:00" if ([self isUniversalTime]) { timeOffsetString = @"Z"; } else if (offset == NSUndefinedDateComponent) { // unknown offset is rendered as -00:00 per // http://www.ietf.org/rfc/rfc3339.txt section 4.3 timeOffsetString = @"-00:00"; } else { NSString *sign = @"+"; if (offset < 0) { sign = @"-"; offset = -offset; } timeOffsetString = [NSString stringWithFormat:@"%@%02ld:%02ld", sign, (long)(offset/(60*60)) % 24, (long)(offset / 60) % 60]; } timeString = [NSString stringWithFormat:@"T%02ld:%02ld:%0l2d%@", (long)[dateComponents hour], (long)[dateComponents minute], (long)[dateComponents second], timeOffsetString]; } // full dateString like "2006-11-17T15:10:46-08:00" NSString *dateString = [NSString stringWithFormat:@"%04ld-%02ld-%02ld%@", (long)[dateComponents year], (long)[dateComponents month], (long)[dateComponents day], timeString]; return dateString; }
おまけ
最初に挙げたプログラムを Xcode で Command Line Tool としてビルドし、実行するとコンソールには以下のように出力される。水平線で区切られた 4 行が、testGetDateObject
の一回の呼び出しによるもので、最初が引数として与えられた RFC3339 形式の日時文字列、2 行目が getDateObject
による変換結果(の NSDate
のインスタンス)、3 行目がそのインスタンスをデフォルトのタイムゾーン(ウチではもちろん JST)で評価した結果、最後の 4 行目は同インスタンスを UTC で評価した結果となっている。
2010-11-24 22:06:14.819 ExpApp[24929:a0b] ---------------------------------------- 2010-11-24 22:06:14.821 ExpApp[24929:a0b] RFC3339 Format: 2010-11-22T12:34:56Z 2010-11-24 22:06:14.824 ExpApp[24929:a0b] NSDate object: 2010-11-22 21:34:56 +0900 2010-11-24 22:06:14.824 ExpApp[24929:a0b] Default TZ: 2010-11-22 21:34:56 +0900 2010-11-24 22:06:14.825 ExpApp[24929:a0b] UTC: 2010-11-22 12:34:56 +0000 2010-11-24 22:06:14.825 ExpApp[24929:a0b] ---------------------------------------- 2010-11-24 22:06:14.825 ExpApp[24929:a0b] RFC3339 Format: 2010-11-22t12:34:56z 2010-11-24 22:06:14.826 ExpApp[24929:a0b] NSDate object: 2010-11-22 21:34:56 +0900 2010-11-24 22:06:14.826 ExpApp[24929:a0b] Default TZ: 2010-11-22 21:34:56 +0900 2010-11-24 22:06:14.826 ExpApp[24929:a0b] UTC: 2010-11-22 12:34:56 +0000 2010-11-24 22:06:14.827 ExpApp[24929:a0b] ---------------------------------------- 2010-11-24 22:06:14.827 ExpApp[24929:a0b] RFC3339 Format: 2010-11-22T12:34:56.123Z 2010-11-24 22:06:14.827 ExpApp[24929:a0b] NSDate object: 2010-11-22 21:34:56 +0900 2010-11-24 22:06:14.828 ExpApp[24929:a0b] Default TZ: 2010-11-22 21:34:56 +0900 2010-11-24 22:06:14.828 ExpApp[24929:a0b] UTC: 2010-11-22 12:34:56 +0000 2010-11-24 22:06:14.828 ExpApp[24929:a0b] ---------------------------------------- 2010-11-24 22:06:14.829 ExpApp[24929:a0b] RFC3339 Format: 2010-11-22t12:34:56.123z 2010-11-24 22:06:14.829 ExpApp[24929:a0b] NSDate object: 2010-11-22 21:34:56 +0900 2010-11-24 22:06:14.829 ExpApp[24929:a0b] Default TZ: 2010-11-22 21:34:56 +0900 2010-11-24 22:06:14.830 ExpApp[24929:a0b] UTC: 2010-11-22 12:34:56 +0000 2010-11-24 22:06:14.830 ExpApp[24929:a0b] ---------------------------------------- 2010-11-24 22:06:14.830 ExpApp[24929:a0b] RFC3339 Format: 2010-11-22T12:34:56+09:00 2010-11-24 22:06:14.831 ExpApp[24929:a0b] NSDate object: 2010-11-22 12:34:56 +0900 2010-11-24 22:06:14.831 ExpApp[24929:a0b] Default TZ: 2010-11-22 12:34:56 +0900 2010-11-24 22:06:14.832 ExpApp[24929:a0b] UTC: 2010-11-22 03:34:56 +0000 2010-11-24 22:06:14.832 ExpApp[24929:a0b] ---------------------------------------- 2010-11-24 22:06:14.832 ExpApp[24929:a0b] RFC3339 Format: 2010-11-22t12:34:56+09:00 2010-11-24 22:06:14.833 ExpApp[24929:a0b] NSDate object: 2010-11-22 12:34:56 +0900 2010-11-24 22:06:14.833 ExpApp[24929:a0b] Default TZ: 2010-11-22 12:34:56 +0900 2010-11-24 22:06:14.834 ExpApp[24929:a0b] UTC: 2010-11-22 03:34:56 +0000 2010-11-24 22:06:14.834 ExpApp[24929:a0b] ---------------------------------------- 2010-11-24 22:06:14.834 ExpApp[24929:a0b] RFC3339 Format: 2010-11-22T12:34:56.123+09:00 2010-11-24 22:06:14.835 ExpApp[24929:a0b] NSDate object: 2010-11-22 12:34:56 +0900 2010-11-24 22:06:14.836 ExpApp[24929:a0b] Default TZ: 2010-11-22 12:34:56 +0900 2010-11-24 22:06:14.836 ExpApp[24929:a0b] UTC: 2010-11-22 03:34:56 +0000 2010-11-24 22:06:14.836 ExpApp[24929:a0b] ---------------------------------------- 2010-11-24 22:06:14.837 ExpApp[24929:a0b] RFC3339 Format: 2010-11-22t12.34.56.123+09:00 2010-11-24 22:06:14.837 ExpApp[24929:a0b] NSDate object: 2010-11-22 12:34:56 +0900 2010-11-24 22:06:14.838 ExpApp[24929:a0b] Default TZ: 2010-11-22 12:34:56 +0900 2010-11-24 22:06:14.838 ExpApp[24929:a0b] UTC: 2010-11-22 03:34:56 +0000 2010-11-24 22:06:14.838 ExpApp[24929:a0b] ---------------------------------------- 2010-11-24 22:06:14.839 ExpApp[24929:a0b] RFC3339 Format: 2010-11-22T12:34:56-05:00 2010-11-24 22:06:14.839 ExpApp[24929:a0b] NSDate object: 2010-11-23 02:34:56 +0900 2010-11-24 22:06:14.839 ExpApp[24929:a0b] Default TZ: 2010-11-23 02:34:56 +0900 2010-11-24 22:06:14.840 ExpApp[24929:a0b] UTC: 2010-11-22 17:34:56 +0000 2010-11-24 22:06:14.840 ExpApp[24929:a0b] ---------------------------------------- 2010-11-24 22:06:14.840 ExpApp[24929:a0b] RFC3339 Format: 2010-11-22T12:34:56.123-05:00 2010-11-24 22:06:14.841 ExpApp[24929:a0b] NSDate object: 2010-11-23 02:34:56 +0900 2010-11-24 22:06:14.841 ExpApp[24929:a0b] Default TZ: 2010-11-23 02:34:56 +0900 2010-11-24 22:06:14.842 ExpApp[24929:a0b] UTC: 2010-11-22 17:34:56 +0000
参考文献
関連リンク
- Protocl Reference - Google Data Protocol (公式ドキュメントより)
- RFC 3339 - Date and Time on the Internet: Timestamps (faqs.org)
- RFC 4287 - The Atom Syndication Format (同上)
- Atom の日付書式は RFC3339準拠。 (寝太郎の江戸風呂。ね!)
- NSDateComponents Class Reference (iOS Reference Library)
関連記事
- 記事一覧を取得する (MacBloggerGlass)
- GData Objective-C Client Library を組み込む (MacBloggerGlass)
- 荻原(2.0)本 (Macをプログラムする; 目次を写してある)
0 件のコメント:
コメントを投稿