What's a good approach to unit test an NSDateFormatter? [duplicate] - swift

This question already has answers here:
Convert string with unknown format (any format) to date
(2 answers)
Closed 6 years ago.
I have an array of dates that I would like to get an NSDate object from, using an NSDateFormatter.
let dates = [
"Tue, 04 Feb 2014 22:03:45 Z",
"Sun, 05 Jun 2016 08:35:14 Z",
"Sun, 05 Jun 2016 08:54 +0000",
"Mon, 21 Mar 2016 13:31:23 GMT",
"Sat, 04 Jun 2016 16:26:37 EDT",
"Sat, 04 Jun 2016 11:55:28 PDT",
"Sun, 5 Jun 2016 01:51:07 -0700",
"Sun, 5 Jun 2016 01:30:30 -0700",
"Thu, 02 June 2016 14:43:37 GMT",
"Sun, 5 Jun 2016 01:49:56 -0700",
"Fri, 27 May 2016 14:32:19 -0400",
"Sun, 05 Jun 2016 01:45:00 -0700",
"Sun, 05 Jun 2016 08:32:03 +0000",
"Sat, 04 Jun 2016 22:33:02 +0000",
"Sun, 05 Jun 2016 01:52:30 -0700",
"Thu, 02 Jun 2016 15:24:37 +0000"
]
I was going with the GWT pattern, but felt strange structuring my unit test like that, because I need to write a dozen or more distinct test funtions for each case.
Can anyone suggest a better approach to this? Or is this an acceptable usage of the "Given, When, Then" pattern?
..I really don't want to have a testRFC822DateFormatter1(), testRFC822DateFormatter2(), testRFC822DateFormatter3(),...
func testRFC822DateFormatter() {
// Given
let rfc822DateFormatter = RFC822DateFormatter()
let dateString = "Tue, 04 Feb 2014 22:03:45 Z"
// When
let date = rfc822DateFormatter.dateFromString(dateString)
// Then
XCTAssertNotNil(date)
let components = NSCalendar.currentCalendar().components([.Year, .Month, .Day, .Hour, .Minute, .Second, .TimeZone, .Calendar], fromDate: date!)
XCTAssertEqual(components.day, 4)
XCTAssertEqual(components.month, 2)
XCTAssertEqual(components.year, 2014)
XCTAssertEqual(components.hour, 22)
XCTAssertEqual(components.minute, 3)
XCTAssertEqual(components.second, 45)
XCTAssertEqual(components.timeZone?.daylightSavingTimeOffset, 3600)
XCTAssertEqual(components.timeZone?.secondsFromGMT, 3600)
XCTAssertEqual(components.calendar?.calendarIdentifier, NSCalendarIdentifierGregorian)
}
Thank you!

There are two kinds of tests you need.
1) A test to ensure that a particular dateFormat works properly with a particular format of date.
2) A test to ensure that if two different dateFormats work on a particular format of date, that they are either both the same or your logic will pick the correct one.
So I would envision one test for each dateFormat and one test for each date that could potentially match more than one format.
For these tests, the GWT pattern is fine as far as I can tell. It's more a matter of identifying all the various date formats you will need to use and making sure that the correct date format is used for each date.
As an aside, I wouldn't be comfortable subclassing NSDateFormatter, nor do I see that it's necessary... For the inputs you specify in your question, the code below is all that's necessary:
let dateFormatter1: NSDateFormatter = {
let result = NSDateFormatter()
result.dateFormat = "EEE, d MMM yyyy HH:mm:ss Z"
return result
}()
let dateFormatter2: NSDateFormatter = {
let result = NSDateFormatter()
result.dateFormat = "EEE, d MMM yyyy HH:mm Z"
return result
}()
let dateFormatter3: NSDateFormatter = {
let result = NSDateFormatter()
result.dateFormat = "EEE, d MMM yyyy HH:mm:ss z"
return result
}()
func dateFromString(dateString: String) -> NSDate? {
return dateFormatter1.dateFromString(dateString) ?? dateFormatter2.dateFromString(dateString) ?? dateFormatter3.dateFromString(dateString)
}
And for the code above, I would expect a total of three tests, one for each date formatter.

Related

flutter HTTP date strings with DateFormat

intl: ^0.16.1
Can't seem to parse HTTP header date field with flutter DateFormat/HttpDate
here is what I tried:
var date = HttpDate.parse("Thu, 11 Feb 2021 10:53:15 +0200");
return error:
Invalid HTTP date Thu, 11 Feb 2021 10:53:15 +0200
Note: the string was received by package:googleapis/gmail/v1.dart
final zFormatDateEmailRFC2822 = DateFormat("EEE, d MMM yyyy HH:mm:ss Z");
var date = zFormatDateEmailRFC2822.parse("Thu, 11 Feb 2021 10:53:15 +0200");
return error:
Trying to read EEE from Thu, 11 Feb 2021 10:53:15 +0200 at position 0
The following is an example from https://api.flutter.dev/flutter/intl/DateFormat-class.html
final fmt = DateFormat('EEE, MMM d, ''yy');
var date = fmt.parse("Wed, Jul 10, '96");
return error:
Trying to read EEE from Wed, Jul 10, '96 at position 0
final fmt = DateFormat("d MMM yyyy");
var date = fmt.parse("11 Feb 2021");
return error:
Trying to read MMM from 11 Feb 2021 at position 3
final fmt = DateFormat("MMM");
var date = fmt.parse("Feb");
return error:
Trying to read LLL from Feb at position 0
The only thing that works for me is:
var dateStr = "Thu, 11 Feb 2021 10:53:15 +0200";
RegExp regExp = RegExp(r"(.*, \d+ .* \d+ \d+:\d+:\d+)");
if (regExp.hasMatch(dateStr)) {
var groups = regExp.firstMatch(dateStr);
var date = HttpDate.parse(groups[1] + " GMT");
print("date $date >${HttpDate.format(date)}<");
}
Try it:
final fmt = DateFormat("d MMM yyyy", "en_US");
var date = fmt.parse("11 Feb 2021");
I had to parse the email header date string
Somehow the other answers where not considering everything i needed and so i came up with the following solution which also takes care of the timezone +0200
DateFormat('E, d MMM yyyy hh:mm:ss Z', 'en_US').parse(DATE_STRING);
Input String : Wed, 18 Aug 2021 09:00:43 +0200
DateTime.toISo8601String() => 2021-08-18T09:00:43.000
DateTime.toUTC().toString() => 2021-08-18 07:00:43.000Z
If you want to learn more about the patterns please have a look at DateFormat

Swift "date from string" conversion doesn't work but the format works with online service?

Code for playground:
var dateStr = "Fri, 03 Aug 2018 08:55:22 GMT"
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.setLocalizedDateFormatFromTemplate("EEE, dd MMM yyyy HH:mm:ss z")
let date = dateFormatter.date(from: dateStr)
In the same time I use the online service - it shows that the format I chose is correct. Where is my mistake?
Small tip when you are working with DateFormatter, if it doesn't work one way, then do it the other way:
let string = dateFormatter.string(from: Date())
print("string: \(string)")
This way you'll see how your format is really interpreted.
If you do so, you'll get:
$> string: Fri, Aug 03, 2018, 12:05:09 GMT
See the extras , and the Aug 03 vs 03 Aug?
Now, your issue is that you misunderstood localizedDateFormatFromTemplate.
In fact you could remove spaces, punctuations and order.
For instance, dateFormatter.setLocalizedDateFormatFromTemplate("ddyyyyHHmmsszEMMM") gives the same output.
You just needs to give it what kind of infos you want (day, year, months, etc.), and it create the correct dateFormat corresponding in the localized version (adding then extra punctuations, etc.).
So use instead:
dateFormatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss z"
Side note:
I currently live in GMT+2, so I added dateFormatter.timeZone = TimeZone(secondsFromGMT: 0) to make it work.
You have to give dateFormatter.dateFormat to convert the string to date format. From the comment you get the answer but for others i am posting a correct answer here.
var dateStr = "Fri, 03 Aug 2018 08:55:22 GMT"
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss z" //Added this line.
let date = dateFormatter.date(from: dateStr)

Cant convert string to NSDate

I'm trying to convert string to NSDate. I suppose that my dateFormat is ok, but i still receive nil.
My code:
let dateStr = tweet.objectForKey("created_at") as! String
print(dateStr)
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "E MMM dd HH:mm:ss Z yyyy"
let date = dateFormatter.dateFromString(dateStr)
print(date)
Output:
Mon Apr 04 20:12:54 +0000 2016
nil
Mon Apr 04 14:17:09 +0000 2016
nil
Mon Apr 04 14:07:32 +0000 2016
nil
Sun Feb 21 12:37:23 +0000 2016
nil
I am using the same code and it's working for me. Assuming, you are getting correct value for dateStr as it is shown in Output.
let dateStr = "Mon Apr 04 20:12:54 +0000 201"
print(dateStr)
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "E MMM dd HH:mm:ss Z yyyy"
let date = dateFormatter.dateFromString(dateStr)
print(date!)
Output:
Mon Apr 04 20:12:54 +0000 2016
2016-04-04 20:12:54 +0000
See attached screenshot

Having trouble converting date String to NSDate [duplicate]

This question already has answers here:
NSDate is 5 hours off
(4 answers)
Closed 6 years ago.
I'm having trouble converting date String to NSDate
Here is my date string:
Fri, 08 Apr 2016 16:59:35 +0300
Trying to convert to NSDate:
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss Z"
let dateFromString : NSDate = dateFormatter.dateFromString("Fri, 08 Apr 2016 16:59:35 +0300")
Return NSDate is:
2016-04-08 13:59:35 +0000
Timezone is wrong. Anyone can help with that?
Try this:
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss Z"
NSTimeZone.setDefaultTimeZone(NSTimeZone(forSecondsFromGMT: 0))
let dateFromString : NSDate = dateFormatter.dateFromString("Fri, 08 Apr 2016 16:59:35 +0300")!
Note that it does not account for DST.

Powershell Convert DateTime to dd mon yyyy

I want to convert a date to this format "dd Mon yyyy".
I have this code which works:
$date = [DateTime]::Parse("21/11/2014")
$dateFormatted = $date.GetDateTimeFormats()[12]
#$dateFormatted displays 21 November 2014
Is there a way to convert it using something like this?:
$dateFormatted = $date.ToString("dd Mon yyyy")
At the moment this returns "21 11on 2014"
I worked it out:
$dateFormatted = $date.ToString("dd MMMM yyyy")