How to change time and timezone in iPhone simulator? - objective-c

How do I change time and time zone in the iPhone simulator?

I'm guessing it uses your system timezone, so changing the TZ in System Preferences would probably do the trick

You can set the TZ environment variable in an Xcode Scheme to set the time zone just for that app.
You can use UTC, PST, EST, as well as place-based timezone names such as America/Los_Angeles. It's not well documented, but I suspect any time zone name should work.
It's not well documented, but the source is an Apple Developer Support rep on the developer forums.

Restart the Simulator after changing the system date time preferences and you shall see the changes reflected. It worked for me.

For the purpose of taking a screenshot, Apple finally made it possible to override time on the status bar of iOS simulator (since Xcode 11) by using simctl tool:
xcrun simctl status_bar "iPhone Xs" override --time "21:08"

Here is a solution available from iOS 13 and Xcode 11 at least. (did not test with previous versions)
[Edit] This will change only the status bar as in the comments!
By default the iOS Simulator shows whatever the time is on your Mac, however, you can use Xcode’s command line to override that with this command in the terminal:
xcrun simctl status_bar "iPhone 11 Pro Max" override --time '9:41'
Replace the simulator name with the device you want to change.
For the status bar you have this overrides:
You may specify any combination of these flags (at least one is required):
--time <string>
Set the date or time to a fixed value.
If the string is a valid ISO date string it will also set the date on relevant devices.
--dataNetwork <dataNetworkType>
If specified must be one of 'wifi', '3g', '4g', 'lte', 'lte-a', or 'lte+'.
--wifiMode <mode>
If specified must be one of 'searching', 'failed', or 'active'.
--wifiBars <int>
If specified must be 0-3.
--cellularMode <mode>
If specified must be one of 'notSupported', 'searching', 'failed', or 'active'.
--cellularBars <int>
If specified must be 0-4.
--batteryState <state>
If specified must be one of 'charging', 'charged', or 'discharging'.
--batteryLevel <int>
If specified must be 0-100.
The time can be any string. But if you want the device to show the date you will need use the ISO format.
For example a valid ISO date string would be '2007-01-09T10:41:00+01:00'
Otherwise you can use the time parameter as a string and it will display whatever you pass in it.
With thanks to the original post by Paul Hudson Here's the link!

This is an old thread but it is closest to my question. I need to simulate time zone for Europe, this method works for me. Go to 'TimeZone' tap instead of 'Date&Time' tap. Uncheck the 'Set time zone automatically using current location' box and slide the vertical rectangle bar (with blue dot on it) to simulate your system time.

When changing the timezone, I found the easiest way to do it was by clicking the clock in the menubar. And then selecting "Open Date & Time Preferences" then select the tab Time Zone.
Alternatively System Preferences -> Date and Time and select the tab Time Zone.
Just a pointer for anyone that might not know their way around OSX.

I have proposed an automatic solution to the problem of changing the time that includes hacky method swizzling: https://stackoverflow.com/a/34793193/829338. I assume that should also work for changing the time zone accordingly.
I needed to test my app automatically, which required changing the sys time. I did, what Tom suggested: happy hacky method swizzling.
For demonstrative purposes, I only change [NSDate date] but not [NSDate dateWithTimeIntervalSince1970:].
First your need to create your class method that serves as the new [NSDate date]. I implemented it to simply shift the time by a constant timeDifference.
int timeDifference = 60*60*24; //shift by one day
NSDate* (* original)(Class,SEL) = nil;
+(NSDate*)date{
NSDate* date = original([NSDate class], #selector(date));
return [date dateByAddingTimeInterval:timeDifference];
}
So far, pretty easy. Now comes the fun part. We get the methods from both classes and exchange implementation (it worked for me in the AppDelegate, but not in my UITests class). For this you will need to import objc/runtime.h.
Method originalMethod = class_getClassMethod([NSDate class], #selector(date));
Method newMethod = class_getClassMethod([self class], #selector(date));
//save the implementation of NSDate to use it later
original = (NSDate* (*)(Class,SEL)) [NSDate methodForSelector:#selector(date)];
//happy swapping
method_exchangeImplementations(originalMethod, newMethod);

My build server is UTC and some of my unit tests needed the timezone to be PST. Using a category on NSTimeZone you can override Apple's implementation to use your code. Works for swift only projects too.
//NSTimeZone+DefaultTimeZone.h
#import <Foundation/Foundation.h>
#interface NSTimeZone (DefaultTimeZone)
+(NSTimeZone *)defaultTimeZone;
#end
//NSTimeZone+DefaultTimeZone.m
#import "NSTimeZone+DefaultTimeZone.h"
#implementation NSTimeZone (DefaultTimeZone)
+(NSTimeZone *)defaultTimeZone
{
return [NSTimeZone timeZoneWithName:#"America/Los_Angeles"];
}
#end

Only working solution for now. XCode does provide option to set a Time Zone for a particular app.
In XCode, Click on your app, Edit Scheme -> Run configuration -> Arguments Tab -> Add Environment Variables
Create a variable with Name: TZ, Value: CST (Any other standard format. XCode didn't explicitly mention the allowed values. But you can use America/Chicago too)

After changing the system date time preferences I had to choose Hardware > Reset All Content And Settings.
Only this worked for me in Version 10.3 (SimulatorApp-880.5 CoreSimulator-681.5.4).

Related

ASP.NET Core API ISO8601 not parsed in local time when suffix is 'Z'

Scenario:
I have a REST-API that takes a POST-Request. As Body-Data there is passed a Datetime in ISO8601 Format.
{
"validate": "2019-12-02T23:00:00Z",
"configuration": {},
"sortId": 1
}
With Modelbinding in MVC the Datetime gets parsed automaticly. The variable should be in the local timezone of the api-server. In this case Europe/Berlin. I would expect the time to be (refering to the example) to be on 2019-12-03:00:00:00. But this is not the case. It is still one hour off.
But when i post the following:
{
"validate": "2019-12-02T23:00:00+00:00",
"configuration": {},
"sortId": 1
}
The parsing into the local timezone works as expected. Because the Client posting the data is written in JS and uses the default Date.toISOString() function, i always get a 'Z' in the ending. According to the ISO8601 this is totally fine.
Z explicitly means UTC. +00:00 doesn't. The UK is at 00:00 now, but 01:00 in the summer. In 1970, summer time (01:00) was used for the entire year.
There are a couple of concepts involved here, and a bit of history. First of all, DateTime has no concept of offset or timezone. A DateTime can only be UTC, Local or Undefined, according to its Kind property.
Using DateTime means that the offset information is lost. The resulting value needs to be converted to something. To do that, the machine's offset is used. That is, the web service machine's offset, not the database server's.
And then, our container or application fails over to a machine with a default UTC timezone instead of our configured timezone. Over the weekend.
It's worth reading Falsehoods programmers believe about time, especially 8. The machine that a program runs on will always be in the GMT time zone.
A better solution would be to use DateTimeOffset, although even that won't be able to handle DST rule changes.
An even better solution would be to use IANA timezone names and pass Europe/Berlin instead of offsets. That's not common usage though. Airlines at least post flight times both with offsets and timezone names.
DateTime Parsing rules
DateTime parsing rules convert Z or offsets to Local with conversion and anything else to Unspecified without conversion. This sounds strange but consider that DateTime was built to work on desktop applications, where Local time makes sense.
This code
var values=new[]{
"2019-12-02T23:00:00+00:00",
"2019-12-02T23:00:00Z",
"2019-12-02T23:00:00"
};
foreach(var value in values)
{
var dt=DateTime.Parse(value);
Console.WriteLine($"{dt:s}\t{dt.Kind}");
}
Produces :
2019-12-03T01:00:00 Local
2019-12-03T01:00:00 Local
2019-12-02T23:00:00 Unspecified
The UTC kind is lost here and, as a developer of flight reservation systems, I don't like that at all. Flight times are in the airport's local time, not my servers. Now I'll have to convert that value back to UTC or something, before saving it to a database. I have to convert it back to the original airport offset to print the tickets and send notifications.
And I'll have to reimburse you guys if there's any error, even if it's due to an airline's error.
JSON.NET (really API) parsing rules
JSON.NET on the other hand, parses strings with Z to UTC, Offsets to Local with conversion and no offset to Undefined. For an API that receives requests from anywhere, UTC is far more useful. Most hosters and cloud services provide UTC machines by default too.
This code :
class It
{
public DateTime Dt{get;set;}
}
var values=new[]{
"{'dt':'2019-12-02T23:00:00+00:00'}",
"{'dt':'2019-12-02T23:00:00Z'}",
"{'dt':'2019-12-02T23:00:00'}"
};
foreach(var value in values)
{
var dt=JsonConvert.DeserializeObject<It>(value).Dt;
Console.WriteLine($"{dt:s}\t{dt.Kind}");
}
Produces :
2019-12-03T01:00:00 Local
2019-12-02T23:00:00 Utc
2019-12-02T23:00:00 Unspecified
Better, but I don't like it. I still lose information.
JSON with DateTimeOffset
DateTimeOffset includes the offset so no information is lost. Unspecified offsets are treated as Local time. This snippet :
class It
{
public DateTimeOffset Dt{get;set;}
}
void Main()
{
var values=new[]{
"{'dt':'2019-12-02T23:00:00+00:00'}",
"{'dt':'2019-12-02T23:00:00Z'}",
"{'dt':'2019-12-02T23:00:00'}"
};
foreach(var value in values)
{
var dt=JsonConvert.DeserializeObject<It>(value).Dt;
Console.WriteLine($"{dt:o}");
}
}
Produces :
2019-12-02T23:00:00.0000000+00:00
2019-12-02T23:00:00.0000000+00:00
2019-12-02T23:00:00.0000000+02:00
Why not UTC everywhere?
Because that loses a lot of information that could easily make that time value unusable. There are a lot of SO questions where the poster tried to compare UTC time and got unexpected results because of DST effects or even DST changes.
A few years back Egypt changed its DST rules with a couple of weeks notice. Airlines and online agents weren't thrilled.
Besides, what if there are more than two timezones in play? International flights rarely land in the same timezone, so storing UTC doesn't work. Airlines don't publish schedules in UTC, they publish them as local time, with offset and IANA TZ names as additional info.
It's worth reading Falsehoods programmers believe about time, especially the parts that refer to UTC or GMT.

How to show year only in NSDatePicker

I want to show year component only in a NSDatePicker.
I tried set/add NSDateFormatter to NSDatePicker, but with no luck. (By dragging a NSDateFormatter to NSDatePicker in nib)
Is there any way to achieve this without subclassing NSDatePicker or NSTextField? Thank you!
After diving into Apple's Documentation, I found the solution and want to post it here, in case it is useful for someone else.
No need to subclass NSDatePicker, there is a method - (void)setDatePickerElements:(NSDatePickerElementFlags)elementFlags which specifies which element the date picker would display. elementFlags is a constant, defined by a enum as:
enum {
NSHourMinuteDatePickerElementFlag = 0x000c,
NSHourMinuteSecondDatePickerElementFlag = 0x000e,
NSTimeZoneDatePickerElementFlag = 0x0010,
NSYearMonthDatePickerElementFlag = 0x00c0,
NSYearMonthDayDatePickerElementFlag = 0x00e0,
NSEraDatePickerElementFlag = 0x0100,
};
typedef NSUInteger NSDatePickerElementFlags;
When looking at those constants, I find it is just a bit mask. Bit place and the corresponding calendar elements is as follows:
15 - 9 bit: Unknown. Maybe unused.
8 bit: Era. (Would not display anything if has a 4-digit year format.)
7 bit: Year.
6 bit: Month.
5 bit: Day.
4 bit: Time zone.
3 bit: Hour.
2 bit: Minute.
1 bit: second.
0 bit: Unknown. Maybe millisecond, or unused.
So, the following line would give me a year only date picker:
[_yearOnlyDatePicker setDatePickerElements:0x0080];
_yearOnlyPicker is an instance of NSDatePicker.
Here is the result:
How yearOnlyDatePicker looks like in Interface Builder:
How yearOnlyDatePicker looks like when running the app:
-[NSDatePicker setDatePickerElements:] can no longer be tricked into showing year only.
A year-only NSDatePicker can be obtained by configuring a year-month picker and subclassing NSDatePickerCell to prevent it from creating the month and separator fields:
- (void)_addSubfieldForElement:(int)arg1 withDateFormat:(id)arg2 referenceStrings:(id)arg3
{
if ((arg1 == 6) || (arg1 == 100)) {
return;
}
[super _addSubfieldForElement:arg1 withDateFormat:arg2 referenceStrings:arg3]; // Private API
}
Please file bug reports with Apple to request a year-only variant of NSDatePicker. I also requested a week-of-year picker.
It is easy you don't need to use NSDatePicker. All you have to do is create a range of years you want and use it as datasource for normal picker.
for (int i=1900; i<=currentYear; i++) {
[_yourDataSourceArr addObject:[NSString stringWithFormat:#"%d",i]];
}

Making NSTimeZone Trouble Free in Unit Tests

So here's the problem with doing unit tests of calendar code in Objective-C: the Timezone contains the information about daylight savings, so you write a test in the summer, expecting sunrise on June 10th to occur at 6:02 am. Your test passes, later, you are running the test when it's not DST and you get a failure, because when you get the timezone, daylightsavings is turned off.
There doesn't seem to be a simple way to just tell it to give you the timezone with dst turned on?
I was thinking about doing a category so that I would intercept the timezone call but that sounds super messy as I don't know what date you are manipulating.
Of course, I could write all my tests to check the timezone setting and then just shift all my expectations but that sounds like the worst of all possible choices.
Region-specific timezones must take into account daylight saving time in order to accurately calculate intervals between two dates (and times). If you aren't interested in this, perhaps you could use a UTC “timezone” instead, which don't change at all.
For example, New Zealand Standard Time is defined as UTC+12:00, and New Zealand Daylight Saving Time is defined as UTC+13:00. Although the local time in New Zealand differs during Daylight Saving Time, the times in UTC+12:00 remain the same (that is, every other country that also uses UTC+12:00 don't magically move forward just because Daylight Saving Time has commenced in New Zealand).
You can achieve this simply by providing that UTC offset as the name:
NSTimeZone *utc_plus12 = [NSTimeZone timeZoneWithName:#"UTC+12:00"];
Find out what UTC offset your region's daylight saving time is based on and use that.
I encountered the similar problem. Finally I found OCMock and saved my life.
If you are using Cocoapods, that will be great! Here is the steps:
Edit your Podfile and add a lines to import OCMock.
target 'YourProjectTests' do
pod 'OCMock'
end
Add import in your unit test class
#import <OCMock/OCMock.h>
Write your test case like this
- (void)testLocalTimezoneFromPDT {
NSTimeZone* timeZone = [NSTimeZone timeZoneWithAbbreviation:#"PDT"];
id timeZoneMock = OCMClassMock([NSTimeZone class]);
OCMStub([timeZoneMock localTimeZone]).andReturn(timeZone);
// Implement your test case
// XCTAssertEqual(...);
}
That code will mock the original [NSTimeZone localTimeZone] method and return
the static value.
In this example, we return the timezone from Pacific Daylight Time (PDT) [GMT-07:00].
When your class call [NSTimeZone localTimeZone], your class will get the timezone we set with OCMock.
Hopes this answer will help you.

Quartz Composer Objective C compare previous with current input

I'm trying to build something that will only fire a command once per keyboard input (as opposed to every frame like QC does natively). In order to do so, I'm trying to listen in on the keyboard inputs (via Freeboard) and compare the current input versus a previous version.
What seems to be happening is the previous version is getting wiped every time the patch executes, so my conditional to compare strings is failing every time. Here's some code to make it a bit clearer:
- (BOOL)execute:(id <QCPlugInContext>)context atTime:(NSTimeInterval)time withArguments:(NSDictionary *)arguments
{
self.outputPrevious=previousCharacter;
if ([self.inputCharacter caseInsensitiveCompare:previousCharacter]){
self.outputText=#"SAME";
}
else {
self.outputText=#"CHANGE";
}
previousCharacter = [NSString stringWithString:self.inputCharacter];
[previousCharacter retain];
return YES;
}
where self.outputText is the text that tells me the result of the if, self.outputPrevious is telling me what the previous character input was, and self.inputCharacter is the current keyboard input.
previousCharacter is defined in the header and instantiated in -init, so it shouldn't be being reset every time.
I've tried pretty much everything with this, so if you have any ideas or insights, that would be awesome. Thanks!
Figured it out eventually. Full solution can be found here

how to properly debug in xCode and Objective-C

I was wondering if there is an effective way to debug problems in xcode while coding in Objective-C. I create webpages constantly and code in jquery and javascript where you can set various alert boxes in different places in your code to determine if your script is properly executing sections. Can you do something like that in xcode to make sure that your script is executing methods properly and creating variables properly?
Thanks
Use the debugger - that's what it is there for! Set breakpoints by clicking in the grey are next to the line of code you want to break on. When this line of code is going to be excuted, the debugger will kick in and highlight the current place in execution. You can hover the cursor over variables in the IDE to examine their values, view the current call-stack (to see here this code has been called from) and get a list of local variables to help track program state. You can modify variable properties here too which often makes debugging simpler.
Execute code line by line by 'Stepping Over' (cmd+shift+o), which executes the current line, 'Stepping Into' (cmd_shift+i) which steps into the current line of code (if it is a function), or 'Stepping Out' to return back up the call stack.
If you want to stick to 'old-school' printf style debugging, go with NSLoging output to console.
NSLog(#"this text appears");
prints the following to the console:
this text appears
To print some basic variable values:
CGFloat pi = 3.14;
NSString *aFloatString = [NSString stringWithFormat:#"%.2f", pi];
NSLog(#"pi is equal to: %#", aFloatString);
Prints:
pi is equa to: 3.14
Standard c formatters can be used in NSLog i.e %d for int, %.2f for a float to 2 decimal places etc. Use %# for NSString*s.
Remember that NSLog will remain in production code unless you #IFDEF it out of release builds (or something similar), so if you don't want a performance hit, or embarrassing console logs to accompany the app you will want to remove them.
I've been known to litter functions that dump the following to console - and it isn't good:
OUTPUT:
Number of vertices is: 1200
<Requested reduction>
Can I kick it?
....
....
YES. I. CAN!
Number of vertices is: 800
Could have done with removing things like that :|
yes, the debugger can do all the things you want to do (just set some breakpoints - right click where you want them - then build&debug)
You can try writing to the console.
NSLog(#"Some status message here");
NSLog(#"The value of myObject is:%#", myObject);
To view the output of your application, while running with Xcode, click Run->Console and you will see all of the output from your application.