NSDate A Live

自己紹介

アイコン

NSDate

  • 日付オブジェクト
  • これをベースに考える

NSDateFormatter

  • strftime
  • 基本的に表示用に使うことを念頭に置いて使う
  • データを保存するための変換には使わない
    • NSDateオブジェクト自体を保存すべき

dateFormatFromTemplate

サンプル

NSString *format = [NSDateFormatter dateFormatFromTemplate:@"EdMMM" options:0 locale:[NSLocale currentLocale]];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:format];
[dateFormatter stringFromDate:[NSDate date]];
// en_US => Thu, Jun 6
// ja_JP => 6月6日(木)

和暦カレンダー

  • iOSの設定でカレンダーが和暦の場合の挙動

和暦時に yyyy の値がおかしい

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd"];
NSString *result = [dateFormatter stringFromDate:stubDate];
// 期待 : 2013-06-06
// 現実 : 0025-06-06

24時間表示

HH の値がiOSの設定の影響を受ける

解決方法

  • locale(とtimeZone)を設定する

Thread-Unsafe

NSDateComponents

  • 1年は365日とは限らない
  • Calendarによって異なる
  • NSDateを操作するときはNSDatecomponetsを経由した方がいい
  • NSDateComponents : NSHipster

NSDate同士の差分を取得

  • components:fromDate:toDate:options:
  • AとBのNSDateのを持つNSDateComponentsを取得

e.g) minuteの差分を得る

NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *dateComponents = [calendar
    components:NSMinuteCalendarUnit fromDate:fromDate toDate:toDate options:0];
[dateComponents minute];
// toDate - fromDate の 分 を取得できる

NSCalendar

  • currentCalendar is slow
  • NSDateFormatter のインスタンス化も遅め
  • Thread-Unsafe

NSCalendar Class Reference EZ-NET: NSDate から年月や日時を取り出す - Objective-C プログラミング

月初/月末を取得する

  • rangeOfUnit:inUnit:forDate:

rangeOfUnit:inUnit:forDate:

e.g) targetDate の月初めを取得

NSCalendar *cal = [NSCalendar currentCalendar];
// inUnit:で指定した単位(月)の中で、rangeOfUnit:で指定した単位(日)が取り得る範囲
NSRange range = [cal rangeOfUnit:NSDayCalendarUnit inUnit:NSMonthCalendarUnit forDate:targetDate];
NSInteger firstDayValue = range.location;

UIDatePicker

  • 表示はiOSの設定に依存
  • Calanderとlocaleを設定する事で、表示をプログラマブルに変更できる
    • iOS5だと動作がちょっとおかしい

e.g.) 和暦の表示のUIDatePicker

UIDatePicker *datePicker = [[UIDatePicker alloc] init];
// 言語は日本語(iOSの設定の書式に該当)
datePicker.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"ja_JP"];
// カレンダーは西暦(iOSの設定のカレンダーに該当)
NSCalendar *gregorian = [[NSCalendar alloc]initWithCalendarIdentifier:NSGregorianCalendar];
gregorian.locale = [NSLocale currentLocale];
datePicker.calendar = gregorian;
datePicker.datePickerMode = UIDatePickerModeDateAndTime;

ここまでのまとめ

  • 出来る限り直接扱うのは NSDate にする
  • NSDateFormatter に 頼りすぎるな
  • 日付を操作するには NSDateComponents が一番
    • ただし冗長になりが…
  • NSCalendar は1種類じゃない
    • 西暦/和暦/タイ歴…

よりNSDateと仲良くなるには

  • NSDateComponents は直接扱うには冗長すぎる
  • NSCalendarNSDateFormatter は安易に使うとパフォーマンスの問題を起こしやすい

We need Library!

現在のライブラリ

erica/NSDate-Extensions · GitHub

  • 安定、率直な実装
  • パフォーマンスの問題

mysterioustrousers/MTDates · GitHub

  • 多機能
  • キャッシュ
  • テストが書かれている
  • APIが少し分かりにく

mirego/MCDateExtensions · GitHub

  • シンプル
  • キャッシュ
  • NSCurrentLocaleDidChangeNotification対応

もっともっと便利なのが欲しい

azu/NSDate-escort · GitHub

Proposal(未着手…)

  • NSDate-Extensions Compatible API
  • Cache & Fast implement
  • Thread safe API
  • Test Test Test!
  • Test multiple languages
  • 100% Code Coverage

A primary purpose of NSDate-escort

誰もが安心して使えるライブラリ

  • できるだけシンプルな実装
  • 複雑すぎる機能は入れない
  • パフォーマンスの問題を発生しにくくする
  • テストをできるだけ書く
  • NSDate を中心に考える(ユーザーが直接扱うのはNSDate)
  • NSDateComponents を考える必要を少なくする

課題

  • どうやってThread safe???
  • prefixは必要??

Contributingissue 待ってます(日本語で大丈夫です)

おわり

参考