preface

This article has strong personal feelings, if you feel uncomfortable, please close as soon as possible. This article is only used as a personal learning record, and you are welcome to reprint or use it within the scope of the license agreement. Please respect the copyright and keep the link to the original text. Thank you for your understanding and cooperation. If you find this site helpful, you can subscribe to this site by RSS, so that you will be able to access this site information in the first time.

The popular science knowledge used in this article is as follows:

  • GMT:(Greenwich Mean Time). This is local time in Greenwich, which used to be the world standard time.
  • UT (Universal Time). According to atomic clocks
  • Coordinated Universal Time (UTC) The position of the sun is related to the rotation of the Earth. In the past, people believed that the rotation rate of the Earth was constant, but this perception was overturned in 1960, when people found that the rotation rate of the Earth was becoming slower and slower, while Time was still moving at a constant rate. So UTC is no longer considered an accurate description of time. We need to keep looking for a constant velocity. From macro to look up into the sky is our direction to find the answer, the development of science and technology let us made a deeper understanding in the micro aspect, and there the wise according to microscopic particles in the physical properties of the atom, established the atomic clocks, as measured by the atomic clocks time, atomic clocks 5 billion error 1 second, the intensive reading has been far more than GMT. This atomic clock reflects Time, which is Coordinated Universal Time (UTC).

Excerpt from: iOS dealing with time

Scene description

In the recent development process, QA students raised a bug, when the date and time of the mobile phone was modified, they found that the page time display was abnormal. This kind of problem is very classic, which is the time processing of iOS.

Our perception of time

Time is linear, that is, at any moment, there is only one absolute value of time on the earth, but because of the difference in time zone or culture, we in the same space and time express or understand the same time differently. For example, 20:00 in Beijing and 21:00 in Tokyo are the same absolute time.

You can think of a standard point as a standard point. Time zone fine tuning to realize the date display for each country in the world.

IOS several ways to get time

1.NSDate

Code implementation

	 - (void)timeIntervalSinceReferenceDate {
    NSDate *date = [NSDate date];
    NSLog(@"date = %lf", date.timeIntervalSinceReferenceDate);
}
Copy the code

The NSDate object encapsulates a single point in time, independent of any particular calendar system or time zone. The date object is immutable and represents an unchanging time interval relative to the absolute reference date (00:00:00 UTC, January 1, 2001), which is standard UTC.

NSDate Output:

2020-12-06 12:28:55.795929+0800 ZGTimeDemo[12177:134289] date = 628921735.795845
Copy the code

Calculate below: 628921735.795845/365/86400 = 19.942977, is the year of 2020, distance is just 19 years in 2001.

If we just print NSDate

NSDate *date = [NSDate date];
NSLog(@"%@",date);
Copy the code

Will be output

The 2020-12-06 06:51:04 + 0000Copy the code

NSDate outputs absolute UTC time, while Beijing time is UTC+8. The output above is +8 hours, which is exactly my current time. So the normal UTC + time zone is the real time and date. Please refer to the figure below for time zone addition and subtraction.

Note: NSDate is controlled by the mobile system time. When you change the display of the time on the mobile phone, the output of NSDate to get the current time will also change. When we were making our App, we knew that NSDate wasn’t reliable because the user might change its value.

2. The function CFAbsoluteTimeGetCurrent ()

Official documentation: Absolute time is measured in seconds relative to the absolute reference date (00:00 GMT, 1 January 2001). A positive value indicates the date after the reference date and a negative value indicates the date before the reference date. For example, the absolute time -32940326 corresponds to 17:54:34 on December 16, 1999. Repeated calls to this function do not guarantee monotonically increasing results. System time may be reduced by synchronization with external time references or by explicit user clock changes.

The concept of CFAbsoluteTimeGetCurrent() is very similar to NSDate, except that the reference point is the absolute value of time at 00:00:00, January 1, 2001, in GMT.

Note: CFAbsoluteTimeGetCurrent () also will change along with the current equipment system time, also may be modified by the user.

3.gettimeofday()

int gettimeofday(struct timeval * __restrict, void * __restrict);
Copy the code

This function gets the UNIX time.

struct timeval now;
struct timezone tz;
gettimeofday(&now, &tz);
NSLog(@"gettimeofday: %ld", now.tv_sec);
Copy the code
gettimeofday: 1607238723
Copy the code
What is UNIX time?

Unix time is the number of seconds that the current time is offset from the reference point based on 00:00:00, January 1, 1970 UTC. The value returned by the API is 1607238723, indicating that the current time has elapsed 1607238723 seconds since 00:00:00, January 1, 1970 UTC.

Unix time is also a commonly used time standard. On the Mac terminal, you can use the following command to convert the time to readable time:

date -r 1607238723
Copy the code

The output

Sunday, 6 December 2020 15:12:03 CSTCopy the code

Note:gettimeofday().NSDate.CFAbsoluteTimeGetCurrentAll three are affected by the system time of the current device. It’s just a different time reference point. We usually use NIX time when communicating with the server.

5.mach_absolute_time()

There is just one such value on our iPhone. It is the ticks of the CPU. This tick is used to describe the time and mach_Absolute_time () returns the number of ticks that the CPU has run. Convert this tick number to seconds or nanoseconds. This is directly related to time. The tick count, however, restarts every time the phone restarts and pauses when the iPhone’s lock screen goes to sleep.

Note:mach_absolute_time()It is not affected by the system time, but by the restart and hibernation behavior of the device

6.CACurrentMediaTime()

CACurrentMediaTime() is the result of converting the CPUtick number of mach_Absolute_time () above into seconds. The following code:

double mediaTime = CACurrentMediaTime();
NSLog(@"CACurrentMediaTime: %f", mediaTime);
Copy the code
ZGTimeDemo[19731:281283] CACurrentMediaTime: 17789.582767Copy the code

Returns the total number of seconds the device has been running (not counting device hibernation) since it was turned on.

This API is equivalent to the following code:

NSTimeInterval systemUptime = [[NSProcessInfo processInfo] systemUptime];
Copy the code

Note:CACurrentMediaTime()It is not affected by system time, but only by device restart and hibernation behavior.

7.sysctl()

IOS also records the last time the device was rebooted. It can be obtained through the following API calls:

#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; }Copy the code

The value returned is the Unix time of the last device restart.

Note: The value returned by this API is also affected by the system time, and if the user changes the time, the value will change as well.

Time synchronization between client and server

Generally, when we initiate a request, the local time is added to the common parameter. If some sensitive interfaces encounter an exception case when users change the system time, an exception will occur. In order to prevent the user from changing the system time by being off the network and affecting the client logic, we usually do this.

  • Get the server at a certain timeAThe time.
  • Record the obtained timeAIs the local timeB;
  • Gets the current local time when time is neededCwhenCBAs a time intervalD,A + DIs the time of the current server.

The key problem is that B and C cannot be affected by the system time. To solve this problem, we need to rely on the interface of iOS — the system running time

First: we rely on the server to give us an accurate timestamp. Each synchronization records one to get the server time stamp b. we just need to use the running time difference to solve the time correction problem.

How long has the system been running?

//get system uptime since last boot - (NSTimeInterval)uptime
{    
    struct timeval boottime;    
    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_sec - boottime.tv_sec;
        uptime += (double)(now.tv_usec - boottime.tv_usec) / 1000000.0;
    }   
    return uptime;
}
Copy the code

Note: This function returns seconds. And the Unix time returned by the server may be multiplied by 1000.(1s = 1000ms)

Both getTimeofday () and sysctl() are affected by system time, but the values obtained by subtracting them are independent of system time. This prevents the user from changing the time. Of course, if the user shuts down and starts up again after a period of time, the obtained time will be slower than the server time. In real scenarios, the time slower than the server time usually has little impact. We generally worry that the client time is faster than the server time.

conclusion

The key to solve the difficulty of this problem is that if the local time is obtained, what we take here is the difference calculation method of system running time. I haven’t tried the amount of time the logic takes to hibernate and unbackground. But I think if you want to do a good tool class, you want to try to calculate the amount of time that is consumed in the background, and you can also get the exact time by calculating the difference of the system running time.

The ABCD synchronization algorithm mainly relies on the time given by the server as a reference point. Another difficulty is how to obtain the running time of the system and calculate the difference value to solve the problem of inaccurate time after the system time is modified by users. The core code is not written as a tool class, so you can implement it by yourself and I’m not going to write the demo. This article is also the first time I switch to jekyll’s first published article. If this article is helpful to you, please bookmark it

The original address