Get Date-Time from internet NTP Server


I post this for everyone who is interesting…

First open a GPRS bearer

  • wip_bearerOpen
  • wip_bearerSetOpts
  • wip_bearerStart

after WIP_BEV_IP_CONNECTED event create an UDP socket:

udp_socket = wip_UDPCreateOpts((wip_eventHandler_f) Socket_Handler, NULL, WIP_COPT_PEER_STRADDR, SocketAddress, WIP_COPT_PEER_PORT, SocketPort, WIP_COPT_END);

where SocketPort must have value 123 and SocketAddress must be an NTP server address

I have test those :

not all NTP servers are working with UDP.

the following code does the main job :

void Socket_Handler(wip_event_t *ev)
	int nRead;							//bytes received
	u8 buffer[200];						//receiving from socket
	s32 sReturn = ERROR;
	ascii NTPHeader[47];				//send this to NTP server
	u32 Seconds1970 = 0x83aa7e80;		//number of seconds from 1900 to 1970
	u32 Seconds1900;					//number of seconds from 1900
	ascii strRsp[200];
	adl_rtcTimeStamp_t * NTPTimeStamp;	//structure to keep the data from NTP server
	adl_rtcTime_t * NTPTime;			//time structure
	ascii CLK_command[30]="AT+CCLK= ";	//command to update the time
	ascii strDate[10];					//variable for date yy/mm/dd
	ascii strTime[10];					//variable for time hh:mm:ss

	switch (ev->kind)
		case WIP_CEV_OPEN:

			adl_atSendResponse( ADL_AT_UNS, "\r\nSocket Openned\r\n" );
			//When the UDP channel is created, send a request to NTP Server
			wip_write(udp_socket, NTPHeader, 48);
		case WIP_CEV_READ:
			adl_atSendResponse( ADL_AT_UNS, "\r\nSocket Read\r\n" );

			//The NTP server replies with a packet with length 48
			//you can get the time with precision, network delay times, ...
			//but in this case we use only the minimum time data
			nRead = wip_read(udp_socket, buffer, sizeof(buffer));
			//You can get the number of seconds that have passed from year 1900. 
			//This is a four byte information and store it to an u32 variable
			Seconds1900 = (buffer[40] * 16777216) + (buffer[41] * 65536) + (buffer[42] * 256) + buffer[43];
			//initialize variables
			NTPTimeStamp = adl_memGet(sizeof(adl_rtcTimeStamp_t)); 
			NTPTime = adl_memGet(sizeof(adl_rtcTime_t));
			//Wavecom counts the seconds from year 1970
			//So we must subtract the number of seconds that have passed till 1970
			NTPTimeStamp->TimeStamp = Seconds1900 - Seconds1970;
			NTPTimeStamp->SecondFracPart = 0;
			//Convert to Date-Time structure
			sReturn = adl_rtcConvertTime(NTPTime,NTPTimeStamp, ADL_RTC_CONVERT_FROM_TIMESTAMP);
			//create date format "yy/mm/dd" and time format "hh:mm:ss"
			wm_sprintf( strDate, "%02d/%02d/%02d", NTPTime->Year, NTPTime->Month, NTPTime->Day);
			wm_sprintf( strTime, "%02d:%02d:%02d", NTPTime->Hour, NTPTime->Minute, NTPTime->Second);
			// Create at+cclk command
			wm_strcat(CLK_command," ");
			//send the command to module
			adl_atCmdCreate(CLK_command,ADL_AT_PORT_TYPE (ADL_AT_UART1,FALSE),Res_CLK_Handler,"*" ,NULL);
			//free memory

			adl_atSendResponse( ADL_AT_UNS, "\r\nSocket Write\r\n" );
			adl_atSendResponse( ADL_AT_UNS, "\r\nSocket Error\r\n" );
			adl_atSendResponse( ADL_AT_UNS, "\r\nSocket Closed\r\n" );


Note the before run at+cclk, you must add UTC Hour offset so the Hour is correct with your country

I wonder if there is any easiest way to move four bytes to u32
(I’m new to C++)

Seconds1900 = (buffer[40] * 16777216) + (buffer[41] * 65536) + (buffer[42] * 256) + buffer[43];

I can get the time with ± 5 seconds precision. You can do much more with NTP protocol.
Also I don’t have error checking code(e.g. if the NTP packet is wrong)

Hi sefer,

Thanks for sharing your code!
I think your information can be useful to a lot of people here…

You can use bit shift operations to make the u32 value. I think it would look like that:

Seconds1900 = (u32)((buffer[40]<<24) + (buffer[41] <<16) + (buffer[42]<<8) + buffer[43]);

You might need the (u32) cast around all buffer items… I’m not sure…

Best Regards,

Hi sefer,
hi jan,

thanks to sefer for sharing the code — it will be usefull for me in the near future :slight_smile:

Jan, I think if it is necessary to cast the result, it must be before the shift operation — otherwise the result of the shift operation will be an u8 value again …

Best regards

Yes - Excellent! :smiley:

I still find it amazing, though, that there is no way to get the date & time direct from the GSM Network! :angry: … light=time

I’ll add a note in that thread pointing to this one. - “the home of the Network Time Protocol project”

See also: viewtopic.php?f=11&t=2646&p=9707#p9707

Implementing from spec is usually best and helps one to understand what happens:
NTPv3: (

But a good example can save you days:
(note the use of doubles - since Java does not have unsigned types, the NTP operations don’t fit into integers as nicely)

Lastly, my personal preference is to keep all back-ends and time references at GMT proper. Only at the point of end-user presentation might it be necessary or useful to show zoned times. This also usually happens on a server with lots of wonderful existing libraries etc to make this easy. Implementing daylight savings time on the modem itself can confuse things.

thank you for your code. it works fine with me too. this is fast and solved my problem. Now i will try to do this in c#.
i found something that seems a mistake. it is this line
wm_sprintf( strDate, “%02d/%02d/%02d”, NTPTime->Year, NTPTime->Month, NTPTime->Day);
NTPTime->Year returns 2008. So you need to get 08 to supply AT+CCLK= command. So i changed your code as follows
wm_sprintf( strDate, “%02d/%02d/%02d”, NTPTime->Year-2000, NTPTime->Month, NTPTime->Day);

Hi to all,
i have a problem implementing the above code. I cannot get an answer from NTP servers.
the traces i get are

"Socket Openned

Socket Write"
and then nothing happens.
the request to the servers is NTPHeader[0]=0x1b or NTPHeader[0]=0x0b??
Neither of them gives me an answer from the server.
i have tried the following servers:

any help is appreciated …

I’m having a problem even opening a “socket”.
wip_UDPCreateOpts returns a NULL.
I tried wip_Create((wip_eventHandler_f) UDPHandler, NULL) so that there could be no addressing mistake and this also returns a NULL and the event handler is not called. (I was going to use wip_writeOpts to set the address in this case).

Can you have a UDP instance as well as a TCP/IP socket open? I have TCP/IP running over GPRS OK. What would stop this even opening?
(I’ve tried various addresses and am reliably informed that the 123 port is accessable.)

Is there a way to get more specific errors out of these functions? I’ve tried scanning the projectname.axf file (how are you supposed to read these? I use TMT for reading the backtrace.axf) but nothing conclusive.


If you are looking for NTP servers to use, the NTP project has set up a ‘pool’ of NTP servers available for public use.

For more info on the NTP server pool, have a look here.

For testing though, it’s probably more polite to set up a server of your own so you don’t get banned from (or break) the pool servers.

ciao, Dave

Well, I’m getting the time now. But it took a while.
Firstly, I did the UDPCreate in a new task. So the UDP “socket” didn’t know about the bearer I had created. I also have two, Ethernet and GPRS.
Apparently the way to tie the UDP to the bearer required is to get the local IP address from the required bearer, then use that in the UDPCreateOpts call with option WIP_COPT_ADDR or WIP_COPT_STRADDR. I just called the function after the GPRS bearer came up from the bearer handler and it started to use that. And vice-versa.
It may have been coincident with other problems I was having, but putting a wip_close at the end of the WIP_CEV_READ seemed to cause problems. I put a delay before it and that was OK. I’ll recheck this later.
I also had a dodgy lead.
Windows seems to sit a listening app on UDP port 123 which can hinder testing on a local network.
And the Wavecom module struggles with busy Ethernet networks, even moderately busy, and slows almost to a stand-still. I have a switch/router shielding it from the rest of the network at the moment.
I’m still having problems with the pool DNS addresses. Sometimes it works, sometimes it doesn’t. If you put in a single server hostname, it always works. Still working on this. It seems only certain servers are responding to me, whether direct or through the pool. Confusing.
I’m trying and if this fails 1,2&3. They all seem to fail once things start failing which doesn’t make sense.
Oh yes, and I had to use 0x1b as the NTP message content. (EDIT: 0xb works OK too)

thanks sefer for the code,it’s very helpful. i also applied the suggestions from others such as the shift and cast operation, and year-2000 for the at+cclk= command part.

now i have a problem, how to take into account Daylight Saving Time? i’ve googled and found out that it’s different,for example in USA: march - nov, in central europe: march- oct .
i want to apply it for germany that uses central europe summer time, but i can’t find any setting in RTC or CCLK command.


Have a look at the NITZ system messages. Date/Time/DST are contained in the +WIND: 15 unsolicited response (amongst other data).

Be aware though, while part of the GSM standard the NITZ messages are network & operator dependent. However, in Oz both the Telstra & Optus SIMs I tested will output the +WIND: 15 network response.

And the start/end dates change occasionally - which is why Microsoft has to keep issuing DST related patches.

ciao, Dave

For my (possibly out-of-date) experience on Vodafone-UK, see: viewtopic.php?f=34&t=748&p=2990&hilit=nitz#p2990

Orange also seems to give NITZ on GPRS registration here.

thank you for the reply.

i didn’t get the +WIND:15 response…even after trying AT+WIND=8192 command.

i’m using vodafone (germany) and maybe they don’t provide NITZ…come to think of it,i think i’ve never seen the WIND:5 response before,bcos it surely catch my attention if i’ve seen something like “vodafone” come out on the screen…

some googling make me realize that actually this whole Daylight Saving Time(DST) is quite a headache to others also…other programming language…server stuff…

right now getting the GMT time from NTP server is the only option for me (and it’s quite good!)…then +1 for my time zone. for DST i could only think of doing this manually,such as comparing the received date if falls between DST (last sunday in March and October for EU) and do that for the next 10 years. the problem is to find the actuall date for next 10 years and save that in my code! i hope there’s some list on the net…

this manual thing is really stupid i think… :unamused:

It certainly is!! :confused:

For this reason, system’s I’ve worked on have always just stuck with GMT for the whole year.

You only really need local DST if you need to display time to people, or synchronise to the activities of people that are affect by DST.

IF you do need it, could you just have some message from your central site that says, “Apply DST offset of X from Y” - or whatever?


Have you tried turning on all the WIND responses? I think it’s AT+WIND=32767…

That’s not good - but from awneil’s comments earlier about Vodaphone maybe they just don’t supply the NITZ response. I haven’t had a chance to use a Vodaphone SIM here in Oz because they don’t have as good coverage as Telstra outside the major population areas here in Oz.

That’s because it’s a political decision, not a scientific one. Here in Oz we have (at least) three time zones on the continent, and some states start DST at beginning of October, some at the end, and some not at all…and occasionally the start dates change (just for the year) when special events are going to occur!

Just give up and keep all your data in UTC. That’s what I do. :smiley:

ciao, Dave

thanks all for your comments and opinions.

in the documentation,it’s only until AT+WIND=16384…and 32767 is not mentioned,so i didn’t try it.

luckily there are equations to calculate DST for europe in Wiki!

I’ve tested it and it works! i’m just putting it here for info to all… :slight_smile:

But, as already noted, so-called “Daylight Saving” is a matter of policy - not mathematics. You have no way to know when (or if) the policy might change…

It’s a bitmap - so I think you mean 16383?

Firmware versions before 6.57 had only 14 bits - so 16383 enabled them all;

Firmware version 6.57 added WIND: 16, enabled by bit 14 - so 32767 enables all of them.