質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

1093閲覧

DataFormatterで文字列から日付型に変更するとnilになってしまう

lilybelly

総合スコア19

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

1クリップ

投稿2019/03/01 18:04

編集2019/03/01 18:05

#メモ型アプリの作成
簡単なメモ型アプリを作成しています。就活のエントリーシート用のメモです。
提出締め切り日の前日にプッシュ通知ができるように、
datePickerからdateを取得して、1日前のdateをcoredata[Memo]のalertDateというプロパティに保存したいです。
##問題部分
しかし、DataFormatterで文字列から日付型に変更するとnilになってしまい、デバックに"baseDateの日付変換に失敗したので本日を使用します"と表示されます。
formatter.date(from: baseDate) がnilにならない方法を教えていただきたいです。

##試したこと
いくつかこのエラーに関して調べてた際に
「locale プロパティに “en_US_POSIX” を指定する」という記事をみつけたので
試してみたんですがうまくいきませんでした。

swift

1func calcDate(day:Int ,hour:Int ,baseDate:String ) -> Date { 2/////////////////該当箇所/////////////////// 3/////////////////////////////////////////// 4 let formatter = DateFormatter() 5// formatter.locale = NSLocale(localeIdentifier: "ja_JP") as Locale 6     //変更部分 7 formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") as Locale 8 // 9 formatter.dateFormat = "yyyy-MM-dd HH:mm:ss" 10 11 var components = DateComponents() 12 13 components.setValue(day,for: Calendar.Component.day) 14 components.setValue(hour,for: Calendar.Component.hour) 15 16 let calendar = Calendar(identifier: Calendar.Identifier.gregorian) 17 18 var base:Date? 19 20 if let _:String = baseDate { 21 print(formatter.date(from: baseDate)) 22 print(baseDate) 23 if formatter.date(from: baseDate) != nil { 24 base = formatter.date(from: baseDate)! 25 } else { 26 print("baseDateの日付変換に失敗したので本日を使用します") 27 base = Date() 28 } 29 30 } else { 31 base = Date() 32 } 33 /////////////////該当箇所/////////////////// 34/////////////////////////////////////////// 35 return calendar.date(byAdding: components, to: base!)! 36 } 37}

##全体コード

swift

1 2import UIKit 3import CoreData 4 5//データを保存する画面 6class ViewController: UIViewController, UITextFieldDelegate,UITextViewDelegate { 7 //それぞれUI部品を定義 8 @IBOutlet var titleField: UITextField! 9 @IBOutlet var memoTextView: UITextView! 10 @IBOutlet var memoNumLabel: UILabel! 11 @IBOutlet var companyField: UITextField! 12 @IBOutlet var dateField: UITextField! 13 14 //coreData(エンティティがMemo) 15 var memo:Memo? 16 17 //UIDatePickerを定義するための変数 18 var datePicker: UIDatePicker = UIDatePicker() 19 //resultDateで1日前を日付計算 20 var resultDate:Date? 21 //MemoTableViewConrtollerから引き渡されたcontext 22 var context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext 23 24 25/* 26 画面が呼ばれる前 27*/ 28 override func viewDidAppear(_ animated: Bool) { 29 super.viewWillAppear(animated) 30 31 } 32 //テキストフィールド以外のところをタップするとキーボードが閉じる 33 @IBAction func tapScreen(_ sender: Any) { 34 self.view.endEditing(true) 35 } 36 37/* 38 画面が呼ばれた時 39*/ 40 override func viewDidLoad() { 41 super.viewDidLoad() 42 titleField.delegate = self 43 memoTextView.delegate = self 44 companyField.delegate = self 45 dateField.delegate = self 46 47 // メモがなければ新規作成 48 if let memo = self.memo{ 49 //メモの値を表示。 50 editedMemo(memo) 51 } 52 53 // ピッカー設定 54 datePicker.datePickerMode = UIDatePicker.Mode.dateAndTime 55 datePicker.timeZone = NSTimeZone.local 56 datePicker.locale = Locale(identifier: "ja") 57 dateField.inputView = datePicker 58 59 // 決定バーの生成 60 let toolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 35)) 61 let spacelItem = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil) 62 let doneItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(ViewController.doneBtn)) 63 toolbar.setItems([spacelItem, doneItem], animated: true) 64 65 // インプットビュー設定(紐づいているUITextfieldへ代入) 66 dateField.inputView = datePicker 67 dateField.inputAccessoryView = toolbar 68 //キーボードを閉じる 69 view.endEditing(true) 70 } 71/* 72 ピッカーのdoneボタン 73*/ 74 75 // UIDatePickerのDoneを押したら発火 76 @objc func doneBtn() { 77 dateField.endEditing(true) 78 79 // 日付のフォーマット 80 let formatter = DateFormatter() 81 //"yyyy年MM月dd日"を"yyyy/MM/dd"したりして出力の仕方を好きに変更できる 82 formatter.dateFormat = "yyyy年MM月dd日H時" 83 //datePickerで指定した日付が表示される 84 dateField.text = "(formatter.string(from: datePicker.date))" 85 let pickerTime = "(formatter.string(from: datePicker.date))" 86 87 //前日,日本時間を設定 88 resultDate = calcDate(day: -1 ,hour: 9 ,baseDate: pickerTime) 89 print(resultDate) 90 } 91 92 //入力ごとに文字数をカウントする 93 func textViewDidChange(_ textView: UITextView) { 94 let str = memoTextView.text 95 let commentNum = memoTextView.text.count 96 //空白と改行を抽出して取り除く 97 let newStr = String(str!.unicodeScalars 98 .filter(CharacterSet.whitespacesAndNewlines.contains) 99 .map(Character.init)) 100 let numLabel = newStr.count 101 memoNumLabel.text = String(commentNum - numLabel) 102 103 } 104 105 func editedMemo(_ memo:Memo){ 106 //編集用に表示 107 titleField.text = memo.title 108 companyField.text = memo.company 109 memoTextView.text = memo.memoText 110 memoNumLabel.text = memo.memoNum 111 dateField.text = memo.memoDate 112 113 } 114 115 @IBAction func saveMemo(_ sender: Any) { 116 //alertの設定 117 let alert: UIAlertController = UIAlertController(title: "メモの登録", message: "この内容で保存しますか?", preferredStyle: UIAlertController.Style.alert) 118 119 // キャンセルボタン 120 let cancelAction: UIAlertAction = UIAlertAction(title: "キャンセル", style: UIAlertAction.Style.cancel, handler:{ 121 // ボタンが押された時の処理を書く(クロージャ実装) 122 (action: UIAlertAction!) -> Void in 123 print("Cancel") 124 }) 125 126 127 // OKボタン押下時のイベント 128 let okAction = UIAlertAction(title: "OK", style: .default) { (action) in 129 130 // 編集の場合は詳細画面から渡されたself.memoを変更、 131 // 新規の場合は新しいMemoオブジェクトを作り、現在の日時を入れる_ 132 let memo: Memo = { 133 if let memo = self.memo { 134 return memo 135 } else { 136 let memo = Memo(context: self.context) 137 memo.createdAt = Date() 138 return memo 139 } 140 }() 141 142 memo.title = self.titleField.text 143 memo.company = self.companyField.text 144 memo.memoText = self.memoTextView.text 145 memo.memoNum = self.memoNumLabel.text 146 memo.memoDate = self.dateField.text 147 memo.alertDate = self.resultDate 148 149 // 上で作成したデータをデータベースに保存 150 (UIApplication.shared.delegate as! AppDelegate).saveContext() 151 152 self.dismiss(animated: true, completion: nil) 153 154 //入力値をクリアにする 155 self.clearData() 156 } 157 158 func didReceiveMemoryWarning() { 159 super.didReceiveMemoryWarning() 160 } 161 162 alert.dismiss(animated: true, completion: nil) 163 164 // ③ UIAlertControllerにActionを追加 165 alert.addAction(cancelAction) 166 alert.addAction(okAction) 167 168 // ④ Alertを表示 169 present(alert, animated: true, completion: nil) 170 171 } 172 // 入力値をクリア 173 func clearData() { 174 titleField.text = "" 175 companyField.text = "" 176 memoTextView.text = "" 177 memoNumLabel.text = "0" 178 dateField.text = "" 179 } 180 181 func textFieldShouldReturn(_ textField: UITextField) -> Bool { 182 //キーボードを隠す 183 textField.resignFirstResponder() 184 return true 185 } 186 187 func applicationWillTerminate(_ application: UIApplication) { 188 self.saveContext() 189 } 190 //データを保存 191 func saveContext () { 192 193 let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext 194 if context.hasChanges { 195 do { 196 try context.save() 197 print(context) 198 199 } catch { 200 let nserror = error as NSError 201 fatalError("Unresolved error (nserror), (nserror.userInfo)") 202 } 203 } 204 } 205 206 func calcDate(day:Int ,hour:Int ,baseDate:String ) -> Date { 207 /////////////////該当箇所/////////////////// 208/////////////////////////////////////////// 209 let formatter = DateFormatter() 210// formatter.locale = NSLocale(localeIdentifier: "ja_JP") as Locale 211 formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") as Locale 212 formatter.dateFormat = "yyyy-MM-dd HH:mm:ss" 213 214 var components = DateComponents() 215 216 components.setValue(day,for: Calendar.Component.day) 217 components.setValue(hour,for: Calendar.Component.hour) 218 219 let calendar = Calendar(identifier: Calendar.Identifier.gregorian) 220 221 var base:Date? 222 223 if let _:String = baseDate { 224 print(formatter.date(from: baseDate)) 225 print(baseDate) 226 if formatter.date(from: baseDate) != nil { 227 base = formatter.date(from: baseDate)! 228 } else { 229 print("baseDateの日付変換に失敗したので本日を使用します") 230 base = Date() 231 } 232 233 } else { 234 base = Date() 235 } 236 /////////////////該当箇所/////////////////// 237/////////////////////////////////////////// 238 return calendar.date(byAdding: components, to: base!)! 239 } 240}

アドバイスいただきたいです。よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

MasakiHori

2019/03/02 01:59

UIDatePicker から受け取った Date を String に変換して関数に渡し、関数内で String を Date に逆変換して利用する意味は何ですか? Date をそのまま渡せばいいのでは?
lilybelly

2019/03/02 03:57

もともとはUIDatePicker から受け取った Dateをそのまま渡そうとしたんですが、Date()はGMTベースにより日本時間と9時間ずれてしまい、一度stringに変換するやり方しかできなかったからです。 calcDateの引数にcalcDate(day: -1 ,hour: 9 ,baseDate: pickerTime)として時間を合わせています。 こちらについてもアドバイスをいただけたら嬉しいです。
MasakiHori

2019/03/02 04:42

ユーザーに見せる時だけtimezoneを合わせて、内部ではDateそのままで使いましょう。Calendarも基本的にはcurrentを使えばいいです。 ていうか、これアメリカで使えないですよね? 審査する人はアメリカにいますけど。
lilybelly

2019/03/02 04:46

お恥ずかしながら、日本時間に合わせないといけないものだと思っていました。 そのままDateで使うようにします。 根本的な質問で申し訳ありませんでした。ご回答いただきありがとうございます!
MasakiHori

2019/03/02 05:24

これはかなり多くの人が勘違いする部分なので仕方ありません。 Date はユーザの場所や言語にかかわらない日時に対する絶対的指標ととらえておけばいいです。 表示に関しても、特殊なことをしない限り、システムの提供するものを使っておけばシステムがいいようにしてくれます。 LocaleやTimezoneを気にしなくてはいけないのは、システム設定を無視して常に日本語で日本時間で表示したいなどの場合です。 あと、Deteのdescriptionはテストやデバッグ用ですので、これをユーザーに見せてはいけません。
lilybelly

2019/03/02 07:46

大変勉強になりました。 ご指摘いただいた部分を修正してアプリ開発進めていきたいと思います。 ありがとうございました。今後ともよろしくお願いいたします。
takabosoft

2019/03/06 06:23

解決したのでしたら、(ご自分で回答を登録するなりして)質問をクローズしてください。
guest

回答1

0

自己解決

文字型から日付型に変更させたかったのですが、
そもそも文字列ではなく最初から日付型で保存してしまって構わないとのアドバイスをいただき、
その通りに行ったところ問題なく開発が進みました。
ご協力していただいたみなさんありがとうございました。

投稿2019/03/10 09:27

lilybelly

総合スコア19

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問