2012-06-30 29 views
9

Tôi đang cố gắng sử dụng NSDateFormatter trong ứng dụng của mình có chuỗi ngày và định dạng nó thành NSDate để tôi có thể thực hiện So sánh ngày, tuy nhiên tôi tìm thấy khi tôi sử dụng dateFromString và định dạng ngày tháng mất một ngày.NSDateFormatter dateFromString trả về ngày không chính xác

NSString *dateString = @"02-06-2012"; 
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 
[dateFormatter setDateFormat:@"dd-MM-yyyy"]; 
NSDate *dateFromString = [[NSDate alloc] init]; 
dateFromString = [dateFormatter dateFromString:dateString]; 
NSLog(@"My Date = %@", dateFromString); 
[dateFormatter release]; 

này kết quả đầu ra để giao diện điều khiển:

My Date = 2012-06-01 23:00:00 +0000

Trả lời

19

tôi không tin rằng câu trả lời của Dhruv là chính xác. Trong thực tế, nó không rõ ràng có bất kỳ vấn đề gì cả. Bạn dường như có một kỳ vọng không chính xác về những gì sẽ xảy ra và/hoặc giải thích những gì đang xảy ra.

NSDate đại diện cho một thời điểm. Khoảnh khắc này không có một tên duy nhất. Nó sẽ được biết đến bởi các tên khác nhau ở những nơi khác nhau và theo các hệ thống đặt tên khác nhau (múi giờ, lịch). NSDate không đối phó với bất kỳ điều này, ngoại trừ lamely trong phương pháp -description của nó, nơi nó có để sản xuất một đại diện chuỗi của thời điểm đó.

Thứ hai, một chuỗi như "02-06-2012" không chỉ định thời điểm chính xác. Trước hết, nó chỉ là một ngày không có thông tin thời gian, do đó, NSDateFormatter chỉ mặc định đến thời điểm đầu tiên cho ngày đó. Thứ hai, nó không xác định múi giờ. Khoảnh khắc đầu tiên của ngày dương lịch là một thời điểm khác nhau trong mỗi múi giờ. Trừ khi bạn chỉ định múi giờ với -setTimeZone: hoặc chuỗi tự cung cấp thông tin múi giờ, NSDateFormatter giả định rằng mọi chuỗi ngày bạn yêu cầu phân tích cú pháp đều nằm trong múi giờ hiện tại.

Vì vậy, đối tượng dateFromString của bạn thể hiện khoảnh khắc đầu tiên của ngày được chỉ định, ngày 02-06-2012, trong múi giờ của bạn. Tôi hy vọng đây là những gì bạn muốn. Tuy nhiên, sau đó bạn bị nhầm lẫn theo cách mà NSDate mô tả chính nó khi đã đăng nhập. Như tôi đã nói, NSDate phải chọn một số "tên" (biểu diễn chuỗi) cho thời điểm nó đại diện và tên nó chọn là khá tùy ý. Những ngày này nó được chọn tên mà thời điểm được biết đến trong UTC. Tôi thu thập từ đầu ra nhật ký được hiển thị trong câu hỏi của bạn rằng bạn đang ở UTC + 0100. Vì vậy, ngày có thể giống như nó là một ngày trước đó nhưng nó thực sự là cùng một thời điểm bạn chỉ định. Nói cách khác, "2012-06-01 23:00:00 +0000" và "2012-06-02 00:00:00 +0100" là hai tên tương đương cho cùng một thời điểm. Bạn chỉ không quen nhìn thấy cái đầu tiên và hiểu sai nó.

Bài học là bạn phải ngừng dựa vào tự mô tả của NSDate để ở trong bất kỳ múi giờ cụ thể nào. Thực sự, bạn không phải dựa vào bất cứ điều gì về nó, vì nó không được ghi lại. Trên thực tế, các tài liệu cho trạng thái -[NSDate description], "Biểu diễn không được đảm bảo duy trì liên tục trên các bản phát hành khác nhau của hệ điều hành".

Giải pháp của Dhruv dường như để giúp đơn thuần chỉ vì nó gây ra NSDateFormatter-[NSDate description] để đồng ý về múi giờ. Nhưng điều đó không đáng tin cậy. Nó sẽ không hoạt động trên Snow Leopard, ví dụ, bởi vì -[NSDate description] đã sử dụng múi giờ địa phương thay vì UTC trong phiên bản đó của khung công tác.

Quan trọng hơn, mặc dù, nó làm thay đổi thời điểm thực tế được đại diện bởi đối tượng NSDate mà bạn nhận được từ việc diễn giải chuỗi ngày tháng của bạn. Tôi nghi ngờ bạn thực sự muốn rằng có một ý nghĩa cụ thể - bạn muốn chuỗi được hiểu là đang ở trong múi giờ địa phương - và giải pháp của ông ngăn cản ý định của bạn.

tl; dr: bạn đã nhận được ngày bạn muốn tất cả cùng; không dựa vào -[NSDate description]; không sử dụng giải pháp của Dhruv

+0

Xin chào Ken, Cảm ơn bạn đã trả lời chi tiết, bạn sẽ khuyên bạn nên làm gì hoặc sử dụng? Trong ứng dụng của tôi, tôi cần kiểm tra bằng hoặc lớn hơn ngày được mã hóa cụ thể mà tôi cần đưa vào ứng dụng của mình. Cảm ơn – MonkeyBlue

+1

Bạn phải quyết định thời điểm bạn thực sự muốn nói. Ngày được mã hóa cứng có nghĩa là được hiểu là đang ở trong một số múi giờ cố định cụ thể (giống như múi giờ của văn phòng công ty bạn) không? Hoặc là nó được cho là được hiểu là đang ở trong múi giờ của người dùng? Nếu trước đây, bạn nên đặt múi giờ cố định trên trình định dạng ngày. Nếu sau này, bạn có thể để nó làm mặc định hoặc bạn có thể đặt nó thành '[NSTimeZone defaultTimeZone]' (hoặc '+ systemTimeZone'). –

+0

Cảm ơn Ken Tôi sẽ cho đi - thời gian cố định về cơ bản là một ngày cụ thể vì vậy nếu bạn mở ứng dụng và dựa vào bất kỳ nơi nào trên thế giới, bạn nên sử dụng ngày cụ thể và xem hôm nay lớn hơn hay bằng nhau, chúng tôi đang thực hiện việc này vì chúng tôi phải hiển thị thông tin khác nhau trong ứng dụng của chúng tôi từ một ngày nhất định. Lời giải thích của bạn cũng có ý nghĩa hơn vì vậy tôi sẽ đánh dấu câu trả lời của bạn. Cảm ơn – MonkeyBlue

49

Hãy thử thêm dòng này để mã của bạn,

[dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT+0:00"]]; 

hoặc

[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]]; 

SWIFT update:

Mã từ quetion,

let dateString = "02-06-2012" 
var dateFormatter = NSDateFormatter() 
dateFormatter.dateFormat = "dd-MM-yyyy" 
var dateFromString : NSDate = dateFormatter.dateFromString(dateString)! 
println("My Date \(dateFromString)") 

Và Giải pháp,

dateFormatter.timeZone = NSTimeZone(name: "GMT") 

HOẶC

dateFormatter.timeZone = NSTimeZone(abbreviation: "GMT+0:00") 
+0

Cảm ơn hoàn hảo. – MonkeyBlue

+0

Đây có phải là giải pháp không chung chung không? Điều gì xảy ra nếu thiết bị không có trên GMT? – Stavash

+4

@stavash Đó là điểm, GMT giống với UTC hoặc Giờ quốc tế. Đó là múi giờ chuẩn hóa mà mọi người có thể sử dụng và nó không bao giờ thay đổi (do thời gian tiết kiệm ban ngày, v.v.). Đây là cách iOS lưu trữ ngày/giờ .... – lnafziger

Các vấn đề liên quan