Разный результат для [NSDate date] на разных устройствах

Для начала я должен сказать, что я установил автоустановку в настройках даты и времени, а часовой пояс одинаков для каждого устройства. Поэтому я использую [NSDate date] для получения метки времени в миллисекундах, затем кодирую в NSData и отправляю на другое устройство. На приемнике данные декодируются и вычитаются с новыми [NSDate date]. Так что я получаю общее время, необходимое для отправки и получения сообщения. Это я подумал, потому что, когда отправителем является iPhone 4 iOS6, а получателем - iPhone 5 iOS7, получатель имеет более раннюю отметку времени, чем отправитель. Я не знаю, почему? Может быть, [NSData date] не самый надежный класс для такого рода операций? Я использую GCDAsyncUdpSocket для отправки/получения UDP.

Отправитель кода

NSData *data2 = [self createRandomNSData:8192];
NSMutableData *dataToSend =[NSMutableData data];
[dataToSend appendBytes:&tag length:sizeof(int)];
long long currentTimeStamp = (long long)([[NSDate date] timeIntervalSince1970]*1000.0);
[dataToSend appendBytes:&currentTimeStamp length:sizeof(long long)];
[dataToSend appendData:data2];
NSLog(@"%i || %lld || %lu",tag, currentTimeStamp,(unsigned long)[dataToSend length]);
[_udpSocket sendData:dataToSend toHost:@"230.0.0.1" port:_port withTimeout:-1 tag:tag];
tag++;

Приемник кода

char* dataBytes = [data bytes];
int inTag;
long long inCurrentTimeStamp;
[data getBytes:&inTag length:sizeof(int)];
[data getBytes:&inCurrentTimeStamp range:NSMakeRange(sizeof(int), sizeof(long long))];
long long currentTimeStamp = (long long)([[NSDate date] timeIntervalSince1970]*1000.0);
long long timeStampDiff = currentTimeStamp - inCurrentTimeStamp;
self.delay = timeStampDiff;
NSLog(@"%i || %lld || %lu",inTag, timeStampDiff,(unsigned long)[data length]);

person Błażej    schedule 06.12.2013    source источник
comment
Вы должны хотя бы показать вывод вызовов NSLog.   -  person Martin R    schedule 14.12.2013
comment
Да о какой разнице вы тут говорите? Вы NSLog это делаете, но не даете результатов.   -  person Tom Harrington    schedule 16.12.2013
comment
что с часовыми поясами? они одинаковы?   -  person holex    schedule 17.12.2013
comment
@holex да часовые пояса одинаковые.   -  person Błażej    schedule 17.12.2013
comment
Почему бы вам не отправить сообщение с «клиента» на «сервер», а затем обратно с вашего «сервера» на «клиентское» устройство, чтобы получить общее время пинга. Чтобы получить значение, которое вы сейчас пытаетесь вычислить, вы можете просто разделить значение на два.   -  person Akshat Singhal    schedule 18.12.2013


Ответы (3)


NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"MM/dd/yyyy hh:mm:ss"];
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]];
NSString *strSystemTime = [dateFormatter stringFromDate:[NSDate date]];

Я столкнулся с той же проблемой и решил ее, установив NSLocale. Я надеюсь, что это решение работает и для вас.

person Nirmalsinh    schedule 18.12.2013

Не используйте длинное значение timeIntervalSince1970 * 1000 NSDate. Используйте timeIntervalSince1970, выраженное как двойное, напрямую. Это сохранит все разрешение даты.

Просто добавьте к своим данным байты, которые имеют размер sizeof(double).

Запишите двойное значение и его поток байтов перед отправкой, а также двойное значение и его поток байтов при получении на удаленном устройстве и сравните их.

Если оба устройства являются телефонами в одной сети, и они автоматически устанавливают свои часы (настройки > общие > дата и время), то их часы должны быть синхронизированы в течение доли секунды.

person Duncan C    schedule 06.12.2013
comment
Разве [[NSDate date] timeIntervalSince1970] без умножения на 1000 не возвращает только секунды, а мне нужны миллисекунды. - person Błażej; 06.12.2013
comment
@Duidi, [[NSDate date] timeIntervalSince1970] возвращает доли секунды с 1970 года. Я бы предложил сохранить его в этом формате, чтобы сохранить всю информацию, а затем умножить его на 1000, когда вам нужно рассчитать миллисекунды. - person Duncan C; 12.12.2013

На приемнике данные декодируются и вычитаются с новыми [NSDate date]

Это проблема. Это не имеет никакого отношения к версии iOS, установленной на устройстве: в общем, если ваши метки времени создаются разными компьютерами, вы не можете их вычесть и ожидать какой-либо точности, потому что часы устройства не синхронизированы. достаточно для измерения задержки в сети из-за перекоса часов.

Рассмотрим такой упрощенный пример: предположим, часы на компьютерах Алисы и Боба отстают на 10 секунд: когда часы Алисы показывают 12:00:00, часы Боба показывают 12:00:10.

Алиса отправляет Бобу свою метку времени, которая говорит 14:23:06. Пакету требуется одна секунда, чтобы достичь Боба, теперь Боб видит 14:23:17, когда пакет прибыл. Если Боб просто вычтет отметку времени Алисы из своей, он сделает вывод, что пакету потребовалось 11 секунд, чтобы добраться до нее.

Если Боб отправит Алисе свою временную метку сейчас, скажем, 14:23:18, Алиса получит ее на одну секунду позже, что по часам Алисы будет 14:23:09. Теперь Алиса сделала бы вывод, что пакету потребовалось -9 (да, минус девять!) секунд, чтобы добраться до него, что не имеет никакого смысла.

К счастью, если справедливо предположить, что задержка одинакова на обоих участках пути туда и обратно, вы можете измерить задержку, исключив рассогласование часов. Идея состоит в том, чтобы получить две пары временных меток, построенных таким образом, что рассогласование часов является фактором в обеих парах, но имеет противоположный знак.

Рассмотрим временные метки из приведенного выше примера:

A1=14:23:06 B1=14:23:17
B2=14:23:18 A2=14:23:09

Каждая пара, A1-B1 и B2-A2, содержит перекос, но в первой паре перекос положительный, а во второй паре отрицательный. Следовательно, если вы усредните две разницы во времени, вы получите задержку туда и обратно.

((B1-A1)+(A2-B2)) / 2 =
(11 + -9) / 2         =
2 / 2                 = 1 second

Этого должно быть достаточно для реализации простой программы для измерения задержки туда и обратно в вашей системе.

person Sergey Kalinichenko    schedule 17.12.2013
comment
[не по теме] Лол... Кажется, у меня такие же шляпы, как и у тебя на SO :P - person tckmn; 18.12.2013
comment
@DoorknobofSnow Я думаю, что у вас есть по крайней мере один другой - секретный, который вы носите прямо сейчас. Как вы его получили, если позволите, я спрошу? - person Sergey Kalinichenko; 18.12.2013
comment
Я на самом деле получил это на мете. Это за получение значка Некроманта. :) - person tckmn; 18.12.2013