IOS Time Processing
Do not have to do the app to deal with time, about the processing of time, there are many doorways, far from a row of API calls, get the current system time so simple. We need to understand the differences between the various APIs related to time, and then design the corresponding mechanism for different scenarios.
The form of time
Before we get into the deep discussion, we need to be sure of a premise: time is linear. At any given moment, there is only one absolute time on this earth, but because of time zones or cultural differences, we have different representations or understandings of the same time in the same space-time. This seemingly straightforward truth is the cornerstone of our understanding of the complex concepts of time. Just as UTF-8 and UTF-16 are all Unicode, 21:00 of Beijing's 20:00 and Tokyo are in fact the same absolute time value.
Gmt
Human understanding of time is still limited, but we can at least be certain: the change of time is uniform. The speed of time forward is even, not fast and slow, so in order to describe time, we also need to find a value, its change is also at a uniform rate of change forward.
You may not believe it, we humans have gone through a long period of exploration in order to find the reference value to accurately describe the current time value. You can try to think about what's going on in your life that is changing over time, and it has the numerical properties that are in absolute constant change over time.
Predecessors found that looking up at the sun is a good way, the sun is always in accordance with the law of "early morning," and "everlasting", you can use the sun in a day where the position to describe the current time. Later, the culture of different regions need to exchange, you here the sun is high, I this may have gone down, so need to have a public all recognized place, to this place the sun's position to do reference, communication will be more convenient. The final selection is the Greenwich Observatory location in London, in Greenwich time as a public time, which is what we call GMT time (Greenwich Mean times).
Utc
The position of the sun is associated with the rotation of the earth, in the past, it was thought that the Earth's rotation rate was constant, but in the 1960 the perception was reversed, and the rate of rotation of the earth was becoming more and more slow, and the rate of time forward was constant, so UTC was no longer considered to be a precise description of time.
We need to continue looking for a constant forward value. Looking up at the sky is where we look for answers from the macroscopic direction, the development of science and technology has led us to a deeper understanding of the micro, so a wise man based on the physical properties of microscopic atoms, set up an atomic clock, the atomic clock to measure the change in time, atomic clocks 5 billion years will be 1 seconds, this intensive reading is far more than GMT. This clock reflects the time that we now use UTC (Coordinated Universal Time) standard.
Next, we'll look at a variety of ways to record time in iOS.
NSDate
NSDate is a class that we usually use a lot more, so let's look at its definition:
NSDate objects encapsulate a single point at time,
Independent to any particular calendrical system or time zone.
Date objects are immutable, representing a invariant time interval relative to a
absolute reference date (00:00:00 U TC on 1 January 2001).
The NSDate object describes an absolute value on the timeline, independent of the time zone and culture, and refers to the value of UTC, January 1, 2001 00:00:00 The absolute time of the moment.
It's important to have a concept here, when we describe time in a programming language, we use the absolute value of a timeline as a reference point, and the reference point plus the offset (in seconds or milliseconds, microseconds, nanoseconds) to describe another point in time.
Understand this, and then look at some of the API calls NSDate is very clear, such as:
nsdate* date = [NSDate date];
NSLog (@ "Current date interval:%f", [date timeintervalsincereferencedate]);
timeintervalsincereferencedate Returns an offset from the reference time, which is 502,945,767 seconds 502945767/86400/365= 15.9483056507,86400 is the number of seconds contained in a day, 365 is roughly the number of days in a year, 15.94 of course is the number of years, calculated is just the difference between the time of 2001.
For example, when I write an article at the moment, the current time is 11:29 Beijing time, look at the output of the following code:
nsdate* date = [NSDate date];
NSLog (@ "Current date:%@", date);
Current date:2016-12-09 03:29:09 +0000. Visible nsdate output is the absolute UTC time, and the time zone of Beijing is utc+8, the above output + 8 hours, just is my current time.
NSDate is not related to the city and the culture, so to show the specific format of the time, we need nsdateformatter and Nstimezone auxiliary.
Another important point about nsdate is that the nsdate is controlled by the time of the mobile phone system. That is, when you modify the time on your phone, the output of the nsdate to get the current time will change as well. When we do the app, knowing this, we know that nsdate is unreliable because the user may modify its value.
Cfabsolutetimegetcurrent ()
The official definition is as follows:
Absolute time are measured in seconds relative to the absolute reference date of the 1 2001 00:00:00 GMT.
A positive value represents a date after the reference date, a negative value represents a date before it.
For example, the absolute time-32940326 are equivalent to December 16th, 1999 at 17:54:34.
Repeated calls to this function does not guarantee monotonically increasing results.
The system time could decrease due to synchronization with external time references or due to a explicit
user change of The clock.
From the above description it is not difficult to see the concept of cfabsolutetimegetcurrent () and nsdate very similar, but the reference point is: GMT as the standard, January 1, 2001 00:00:00 This moment the absolute value of time.
The same cfabsolutetimegetcurrent () will also change with the current device's system time, or it may be modified by the user.
Gettimeofday
The API can also return a value that describes the current time, and the code is as follows:
struct Timeval now;
struct timezone tz;
Gettimeofday (&now, &tz);
NSLog (@ "Gettimeofday:%ld", now.tv_sec);
The value obtained using Gettimeofday is UNIX time. What about Unix time?
The Unix time is the number of seconds that the base point is offset from the current time, based on UTC January 1, 1970 00:00:00. The above API returns a value of 1481266031, indicating that the current time distance UTC January 1, 1970 00:00:00 has passed 1,481,266,031 seconds altogether.
Unix time is also usually a more time-consuming standard we use, at the Mac terminal can be converted to the following command to read the time:
In fact, NSDate also has an API that can return UNIX time:
nsdate* date = [NSDate date];
NSLog (@ "timeIntervalSince1970:%f", [date timeIntervalSince1970]);
Gettimeofday and Nsdate,cfabsolutetimegetcurrent () are all affected by the system time of the current device. It's just a reference to the time Datum point is not the same. We typically use Unix time when we communicate with the server.
Mach_absolute_time ()
Mach_absolute_time () may use less students, but this concept is very important.
As mentioned above we need to find a uniform variable attribute value to describe the time, and on our iphone there is just one such value exists, the CPU clock cycle number (ticks). This tick value can be used to describe time, and mach_absolute_time () returns the number of tick that the CPU has already run. Converting this tick number to a number of seconds, or nanoseconds, is directly associated with time.
But this tick number, after each restart of the phone, will start counting again, and the iphone lock screen into hibernation after tick will also suspend the count.
Mach_absolute_time () is not affected by system time and is only affected by device restart and hibernate behavior.
Cacurrentmediatime ()
Cacurrentmediatime () may come into contact with more classmates, first look at the official definition:
/* Returns The current coreanimation absolute time. This was the result of
* calling Mach_absolute_time () and converting the units to seconds. * * Cftimeinterval
Cacur Rentmediatime (void)
Cacurrentmediatime () is the result of converting the number of CPU tick above mach_absolute_time () to a number of seconds. The following code:
Double mediatime = Cacurrentmediatime ();
NSLog (@ "Cacurrentmediatime:%f", mediatime);
The return is that the device is running after the boot (device hibernation is not counted) how many seconds, another API can return the same value:
Nstimeinterval systemuptime = [[Nsprocessinfo processinfo] systemuptime];
NSLog (@ "SystemUpTime:%f", systemuptime);
Cacurrentmediatime () is also unaffected by system time and is only affected by device restart and hibernate behavior.
Sysctl
The iOS system also records the last time the device was restarted. Can be obtained from the following API call:
#include <sys/sysctl.h>
-(long) boottime
{
#define MIB_SIZE 2
int mib[mib_size];
size_t size;
struct Timeval boottime;
Mib[0] = Ctl_kern;
MIB[1] = kern_boottime;
size = sizeof (boottime);
if (Sysctl (MIB, Mib_size, &boottime, &size, NULL, 0)!=-1)
{return
boottime.tv_sec;
}
return 0;
}
The value returned is the Unix time of the last device reboot.
The value returned by this API will also be affected by the system time, and the value will change as the user modifies the time.
With all the means to get time, let's take a look at some of the specific applications under the scenes.
Scene One, time measurement
When we do performance optimization, it is often necessary to record the time that a method is executed, and it is necessary to use some of the methods mentioned above to get the time.
When we do the benchmark of the method execution time, we get the time to meet two requirements, one is high intensive reading, but the API itself consumes little CPU time.
Client-side performance optimization is generally for the flow of the main thread, and we know that the UI thread if encountered more than 16.7ms blocking, there will be dropped frame phenomenon, so we focus on the time of intensive reading is actually in the millisecond (ms) level. We write client code, basically is in the MS this dimension, if a method loss is 0.1ms, we can think that this method for fluency is safe, if often see more than 1ms or a few MS methods, the main thread appears the chance of cotton will become higher.
The above several methods of acquiring time are sufficient, such as a NSDATEAPI call to return the intensive reading is 0.000004 S, that is, 4 microseconds, Cacurrentmediatime () The return of the intensive reading is also in the microsecond level, intensive reading is in line with the requirements. However, there is a view that nsdate belongs to the class of encapsulation, the OOP advanced language itself will be caused by the loss may affect the final actual result, in doing benchmark than C function call accurate, in order to verify this argument, I wrote a simple test code:
int testcount = 10000;
Double avgcost = 0;
for (int i = 0; i < Testcount i + +) {
nsdate* begin = [NSDate date];
NSLog (@ "A meaningless log");
Avgcost + +-[begin Timeintervalsincenow];
}
NSLog (@ "benchmark with NSDate:%f", avgcost/testcount);
avgcost = 0;
for (int i = 0; i < Testcount i + +) {
double starttime = Cacurrentmediatime ();
NSLog (@ "A meaningless log");
Double endtime = Cacurrentmediatime ();
Avgcost + = (endtime-starttime);
}
NSLog (@ "benchmark with Cacurrentmediatime:%f", Avgcost/testcount);
The output results are:
Benchmark with nsdate:0.000046
benchmark with cacurrentmediatime:0.000037
You can see the Cacurrentmediatime and NSDate code itself in a few microseconds, and we do UI performance optimization of the dimensions at the millisecond level, a few microseconds differences will not affect our final judgment results. So using NSDate to do benchmark is completely feasible, here are two macros I use:
#define TICK NSDate *starttime = [NSDate Date]
#define tock NSLog (@ "Time Cost:%f",-[starttime Timeintervalsincenow])
Scenario Two: Time synchronization between the client and the server
This is also the scene that we often encounter, for example, the electric business app to the 0 point of time to start snapping, such as merchandise limit the countdown and so on, this scenario requires us to the client's time and server to maintain consistency, the most important thing is to prevent users through the network to modify the system time, to affect the logic of the client.
More commonly, in some common server interface with the server time, each call interface, the client and server time to do a synchronization and record, but the problem is how to prevent users to modify it?
The nsdate,cfabsolutetimegetcurrent,gettimeofday,sysctl mentioned above all follow the change of the system time, Mach_absolute_ Time and Cacurrentmediatime, although based on the number of CPU clocks, are not affected by the timing of the system, but are still affected during hibernation and restart. It doesn't look right, I'll introduce myself here.
First of all, it will depend on the interface and server time to do synchronization, each synchronization record a servertime (Unix time), while recording the current client value Lastsynclocaltime, then the local time after the time to take Curlocaltime first, Calculate the offset, plus servertime to get the time:
uint64_t reallocaltime = 0;
if (servertime!= 0 && lastsynclocaltime!= 0) {
reallocaltime = servertime + (curlocaltime-lastsynclocaltim e);
} else {
reallocaltime = [[NSDate date] timeintervalsince1970]*1000;
}
If you have never synchronized with the server time, you can only take the local system time, this situation has little impact, indicating that the client has not been used.
The key is that if you get local time, you can use a little trick to get how long the system is currently running, and to log the current client's time with the system's Running time:
Get system uptime since the last boot
-(nstimeinterval) uptime {struct timeval
;
int mib[2] = {ctl_kern, kern_boottime};
size_t size = sizeof (boottime);
struct Timeval now;
struct timezone tz;
Gettimeofday (&now, &tz);
Double uptime =-1;
if (Sysctl (MIB, 2, &boottime, &size, NULL, 0)!=-1 && boottime.tv_sec!= 0)
{
uptime = now.tv_s ec-boottime.tv_sec;
Uptime + = (double) (now.tv_usec-boottime.tv_usec)/1000000.0;
}
return uptime;
}
Both Gettimeofday and sysctl are affected by the system time, but they do a subtraction value that has nothing to do with the system time. This will prevent the user from modifying the time. Of course, if the user shutdown, after a period of time to boot, will lead to the time we get slow and server time, the real scene, slower than the server time often less impact, we are generally worried that the client time faster than the server time.
Multiple and server do time synchronization, and then the key time verification logic on the server side, there will be no unexpected bugs.
Summarize
The logic of time processing summed up here, the key is our understanding of the time itself, to express the various ways of time understanding, understanding the principles behind to choose the right tool.
Thank you for reading, I hope to help you, thank you for your support for this site!