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

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

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

Swift Playgroundは、Swiftをインタラクティブに習得できるiPad向けのアプリケーション。コーディングの知識は一切必要なく、Swift Playgrounds上でプログラミングしたコードによりドローン・ロボットを自在に動かすことが可能です。

Swift

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

Swift 2

Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。

Q&A

解決済

1回答

2809閲覧

String(例:20220618)をDate型にした時に9時間ズレるのを調整したい

Risney

総合スコア148

Swift Playground

Swift Playgroundは、Swiftをインタラクティブに習得できるiPad向けのアプリケーション。コーディングの知識は一切必要なく、Swift Playgrounds上でプログラミングしたコードによりドローン・ロボットを自在に動かすことが可能です。

Swift

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

Swift 2

Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。

0グッド

0クリップ

投稿2022/06/18 08:15

編集2022/06/18 09:41

前提

以下の条件の場合にダイアログを表示したい
・日付ピッカーで選択した日付が、今日と比べて30日以降だった場合

実現したいこと

ピッカーで選択した値のString(例:20220618)をDate型にしたい

発生している問題・エラーメッセージ

Date型には変換できるのですが、
ピッカーで選択した値の1日前の日に変換されてしまいます。(以下は例です)
・ピッカーで選択した値:20220618
・Date型に変換後の値:2022-06-17 15:00:00 +0000

該当のソースコード

dateSelected には「20220618」という文字列が入っています。

swift

1let selectedValue = DateUtils.dateFromString(string: dateSelected, format: "yyyyMMdd") 2print(selectedValue) // 2022-06-17 15:00:00 +0000 3 4let today = Date() 5let after30Days = Calendar.current.date(byAdding: .day, value: 30, to: today)! 6print(after30Days) // 2022-07-18 07:45:26 +0000 7 8// 判定のif文 9if selectedValue > after30Days { 10 // ダイアログ表示メソッド 11}

dateFromString メソッド

swift

1import Foundation 2 3class DateUtils { 4 class func dateFromString(string: String, format: String) -> Date { 5 let formatter: DateFormatter = DateFormatter() 6 formatter.dateFormat = format 7 return formatter.date(from: string)! 8 } 9}

試したこと①

1日前になってしまっているのではなく、
9時間ズレてしまっているのではないかと思い、
dateFromString メソッドに以下を追加したが何もかわらず、、

swift

1formatter.calendar = Calendar(identifier: .gregorian) 2formatter.locale = Locale(identifier: "ja_JP")

試したこと②

記事を参考に以下を追加してもダメでした。
参考:【Swift4】Date()の9時間のズレを調整【Date】

swift

1formatter.timeZone = TimeZone.current 2formatter.locale = Locale.current

試したこと③

UTCだと9時間ズレてしまうみたいなので、
明示的にロケールとタイムゾーンを指定する。
※多分、試したこと②とやっていることはかわらない

swift

1formatter.locale = Locale(identifier: "ja_JP") 2formatter.timeZone = TimeZone(identifier: "JST")

引き続き自分でも調査いたしますが、
有識者の方の力をお借りできれば幸いです。

よろしくお願いいたします。

補足情報(FW/ツールのバージョンなど)

参考:dateFromString:

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

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

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

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

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

guest

回答1

0

ベストアンサー

https://qiita.com/rinov/items/bff12e9ea1251e895306

SwiftはDateをprintするとUTCの時刻が表示されますよね。
そのまま使って良いのかなと思いました。
(リンク先の記事によりますとフォーマット時にロケール・タイムゾーンを設定した方が良いそうではあります)

「2022-06-17 15:00:00 +0000」は日本標準時の2022年6月18日0時ですが、
「2022-06-18 00:00:00 +0000」は日本標準時の2022年6月18日9時になってしまうと思います。


コメントありがとうございます。
追記です。

「20220618」という時間情報がないString

この認識は大切かもしれませんね。
Date型は内部的にはUTCで時刻を保持している感じですが、
タイムゾーンのことを意識しなくても済むようにしてくれるみたいです。
ですので、日付を扱うところはDate型で統一して扱う感じにして、
画面に表示するようなところでタイムゾーンを考慮して変換してあげる感じになるのでしょうか。

1日ズレることになりませんかね?

ちょっと確認してみました。

swift

1let calendar = Calendar.current 2let formatter = DateFormatter() 3formatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "yyyy-MM-dd HH:mm:ss", options: 0, locale: Locale(identifier: "ja_JP")) 4 5let d1 = formatter.date(from: "2022-06-18 08:00:00")! 6print(d1) // 2022-06-17 23:00:00 +0000 7print(formatter.string(from: d1)) // 2022/06/18 8:00:00 8 9// UTCでは23時(前日扱い)になるDateから日付部分だけを取り出して確認 10let c1 = calendar.dateComponents([.year, .month, .day], from: d1) 11let d2 = calendar.date(from: c1)! 12print(d2) // 2022-06-17 15:00:00 +0000 13print(formatter.string(from: d2)) // 2022/06/18 0:00:00

UTCでは23時で前日になるとしても、
日付部分だけを取り出すと、
(処理しているPCのタイムゾーンをうまく考慮してくれているみたいで?)
6月18日として扱ってくれました。

以下のコードの応用でJST形式でprintすることはできました!

ちゃんと自分で試して理解しているようで何よりです!

投稿2022/06/18 09:15

編集2022/06/21 08:32
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

Risney

2022/06/18 09:39

コメントありがとうございます。 > SwiftはDateをprintするとUTCの時刻が表示されますよね。 printの結果だけなら良いのですが、「Debug area」の「Variables view」内の値もUTC時刻なのですが、そのまま比較してよいのでしょうか? 試したことにも記載しましたが、ロケールとタイムゾーンを指定してもダメでした、、
退会済みユーザー

退会済みユーザー

2022/06/18 09:50 編集

> そのまま比較してよいのでしょうか? DateはUTCで統一して扱っているということで、そのまま比較して良いと思います。 after30DaysもUTCで扱われていると思います。 回答のところに書き忘れました・・ +0000はタイムゾーン指定子で、UTCを表すみたいです。 https://ja.wikipedia.org/wiki/ISO_8601#タイムゾーン指定子 「2022-06-17 15:00:00 +0000」という表記と 「2022-06-18 00:00:00 +0900」という表記は 同じ時刻?を指すことになるみたいです。 表記が異なるだけみたいです。
Risney

2022/06/21 07:44 編集

比較対象がどちらもUTCなので問題ないように思えたのですが、 なんだか時間によっては日付の比較のメソッドが上手くいかない気がしてしまいました。 もし仮に、JSTの時間で「2022-06-18 08:00:00(dateSelectedが20220618)」に ピッカーを選択するとします。 UTC表記だと`after30Days`は「2022-07-17 23:00:00 +0000」になり、 `selectedValue `は「2022-06-18 15:00:00 +0000」になることで、 1日ズレることになりませんかね? 「20220618」という時間情報がないStringから日付形式にフォーマットしたものと、 「Date()」から取得した時間情報があるものを比較した結果なのかと、、 別件ですが、 以下のコードの応用でJST形式でprintすることはできました! ```swift let calendar = Calendar(identifier: .gregorian) // 西暦を指定 let firstDay = calendar.date(from: DateComponents(year: 2020, month: 2))! // day: 1 を指定してもよいが省略しても月初となる let dateFormatter: DateFormatter = { let formatter = DateFormatter() formatter.calendar = Calendar(identifier: .gregorian) // 西暦を指定 // formatter.timeZone = TimeZone(identifier: "Asia/Tokyo") // システムのタイムゾーンが Asia/Tokyo でない場合は指定が必要 formatter.dateFormat = "yyyy-MM-dd" return formatter }() print(dateFormatter.string(from: firstDay)) // 2020-02-01 ```
Risney

2022/06/23 06:26

コメントの追記確認いたしました。 画面に表示せずに、単純に内部で比較するだけなら、 そのままで良いってことですね!! 色々と一緒に確認していただきたありがとうございました! ベストアンサーとさせて頂きます。 また、何かあれば宜しくお願いいたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問