importdatetimeimportjsonimportosimporturllib.requestNODE_URL=os.getenv('NODE_URL','https://whydah.symbolmain.net:3001')print(f'Using node {NODE_URL}')try:# Fetch Nemesis timestampproperties_path='/network/properties'print(f'Fetching network properties from {properties_path}')withurllib.request.urlopen(f'{NODE_URL}{properties_path}')asresponse:response_json=json.loads(response.read().decode())nemesis_datetime=datetime.datetime.fromtimestamp(int(response_json['network']['epochAdjustment'].rstrip('s')),tz=datetime.timezone.utc)# Fetch current network timestamptime_path='/node/time'print(f'Fetching current network time from {time_path}')withurllib.request.urlopen(f'{NODE_URL}{time_path}')asresponse:response_json=json.loads(response.read().decode())network_ms=int(response_json['communicationTimestamps']['receiveTimestamp'])network_datetime=nemesis_datetime+datetime.timedelta(milliseconds=network_ms)print(f'\nNemesis time (UTC): {nemesis_datetime}')print(f'Network time (ms since Nemesis): {network_ms}')print(f'Network time (UTC): {network_datetime}')exceptExceptionaserror:print(error)
constNODE_URL=process.env.NODE_URL||'https://whydah.symbolmain.net:3001';console.log(`Using node ${NODE_URL}`);try{// Fetch Nemesis timestampconstpropertiesPath='/network/properties';console.log(`Fetching network properties from ${propertiesPath}`);constpropertiesResponse=awaitfetch(`${NODE_URL}${propertiesPath}`);constpropertiesJson=awaitpropertiesResponse.json();constnemesisStr=propertiesJson.network.epochAdjustment;constnemesisSeconds=parseInt(nemesisStr.replace('s',''),10);constnemesisDatetime=newDate(nemesisSeconds*1000);// Fetch current network timestampconsttimePath='/node/time';console.log(`Fetching current network time from ${timePath}`);consttimeResponse=awaitfetch(`${NODE_URL}${timePath}`);consttimeJson=awaittimeResponse.json();constnetworkMs=BigInt(timeJson.communicationTimestamps.receiveTimestamp);constnetworkDatetime=newDate(nemesisDatetime.getTime()+Number(networkMs));console.log(`\nNemesis time (UTC): ${nemesisDatetime.toISOString()}`);console.log(`Network time (ms since Nemesis): ${networkMs}`);console.log(`Network time (UTC): ${networkDatetime.toISOString()}`);}catch(error){console.error(`Error: ${error.message}`);}
//JAVA 21+//DEPS org.symbol:symbol-sdk:3.3.1importjava.io.IOException;importjava.net.URI;importjava.net.http.HttpClient;importjava.net.http.HttpRequest;importjava.net.http.HttpResponse;importjava.net.http.HttpResponse.BodyHandlers;importjava.time.Instant;importcom.fasterxml.jackson.databind.JsonNode;importcom.fasterxml.jackson.databind.ObjectMapper;publicfinalclassNetworkTime{privatestaticfinalObjectMapperJSON_MAPPER=newObjectMapper();privatestaticfinalHttpClientHTTP_CLIENT=HttpClient.newHttpClient();privatefinalStringnodeUrl=System.getenv().getOrDefault("NODE_URL","https://whydah.symbolmain.net:3001");publicstaticvoidmain(finalString[]args){try{newNetworkTime().run();}catch(finalExceptionex){System.out.println(null==ex.getMessage()?ex.toString():ex.getMessage());}}privatevoidrun()throwsIOException,InterruptedException{System.out.printf("Using node %s%n",nodeUrl);// Fetch Nemesis timestampfinalStringpropertiesPath="/network/properties";System.out.printf("Fetching network properties from %s%n",propertiesPath);finalHttpRequestpropertiesRequest=HttpRequest.newBuilder(URI.create(nodeUrl+propertiesPath)).GET().build();finalHttpResponse<String>propertiesResponse=HTTP_CLIENT.send(propertiesRequest,BodyHandlers.ofString());finalJsonNodepropertiesJson=JSON_MAPPER.readTree(propertiesResponse.body());finalStringnemesisStr=propertiesJson.get("network").get("epochAdjustment").asText();finallongnemesisSeconds=Long.parseLong(nemesisStr.replace("s",""));finalInstantnemesisDatetime=Instant.ofEpochSecond(nemesisSeconds);// Fetch current network timestampfinalStringtimePath="/node/time";System.out.printf("Fetching current network time from %s%n",timePath);finalHttpRequesttimeRequest=HttpRequest.newBuilder(URI.create(nodeUrl+timePath)).GET().build();finalHttpResponse<String>timeResponse=HTTP_CLIENT.send(timeRequest,BodyHandlers.ofString());finalJsonNodetimeJson=JSON_MAPPER.readTree(timeResponse.body());finallongnetworkMs=timeJson.get("communicationTimestamps").get("receiveTimestamp").asLong();finalInstantnetworkDatetime=nemesisDatetime.plusMillis(networkMs);System.out.printf("%nNemesis time (UTC): %s%n",nemesisDatetime);System.out.printf("Network time (ms since Nemesis): %d%n",networkMs);System.out.printf("Network time (UTC): %s%n",networkDatetime);}}
properties_path='/network/properties'print(f'Fetching network properties from {properties_path}')withurllib.request.urlopen(f'{NODE_URL}{properties_path}')asresponse:response_json=json.loads(response.read().decode())nemesis_datetime=datetime.datetime.fromtimestamp(int(response_json['network']['epochAdjustment'].rstrip('s')),tz=datetime.timezone.utc)
constpropertiesPath='/network/properties';console.log(`Fetching network properties from ${propertiesPath}`);constpropertiesResponse=awaitfetch(`${NODE_URL}${propertiesPath}`);constpropertiesJson=awaitpropertiesResponse.json();constnemesisStr=propertiesJson.network.epochAdjustment;constnemesisSeconds=parseInt(nemesisStr.replace('s',''),10);constnemesisDatetime=newDate(nemesisSeconds*1000);
finalStringpropertiesPath="/network/properties";System.out.printf("Fetching network properties from %s%n",propertiesPath);finalHttpRequestpropertiesRequest=HttpRequest.newBuilder(URI.create(nodeUrl+propertiesPath)).GET().build();finalHttpResponse<String>propertiesResponse=HTTP_CLIENT.send(propertiesRequest,BodyHandlers.ofString());finalJsonNodepropertiesJson=JSON_MAPPER.readTree(propertiesResponse.body());finalStringnemesisStr=propertiesJson.get("network").get("epochAdjustment").asText();finallongnemesisSeconds=Long.parseLong(nemesisStr.replace("s",""));finalInstantnemesisDatetime=Instant.ofEpochSecond(nemesisSeconds);
The Nemesis block creation time is a fixed network property and can be retrieved using the /network/propertiesGET
endpoint.
The returned value (epochAdjustment), after removing the s suffix and converting it to an integer, is a
UNIX timestamp.
That is, the number of non-leap seconds that have elapsed since the Unix epoch (00:00:00 UTC on 1 January 1970).
This tutorial retrieves it from the network for illustration purposes, but this is a fixed value and can be
treated as a constant and hardcoded if desired.
For Symbol's main network, the value is 1615853185 which corresponds to 2021-03-16T00:06:25Z
(March 16, 2021 at 12:06:25 AM UTC).
Note that the Symbol protocol and client are open source and can therefore be used to deploy networks other than
the Symbol main network.
Such networks might use different nemesis creation times or represent time values in different formats.
time_path='/node/time'print(f'Fetching current network time from {time_path}')withurllib.request.urlopen(f'{NODE_URL}{time_path}')asresponse:response_json=json.loads(response.read().decode())network_ms=int(response_json['communicationTimestamps']['receiveTimestamp'])
consttimePath='/node/time';console.log(`Fetching current network time from ${timePath}`);consttimeResponse=awaitfetch(`${NODE_URL}${timePath}`);consttimeJson=awaittimeResponse.json();constnetworkMs=BigInt(timeJson.communicationTimestamps.receiveTimestamp);
finalStringtimePath="/node/time";System.out.printf("Fetching current network time from %s%n",timePath);finalHttpRequesttimeRequest=HttpRequest.newBuilder(URI.create(nodeUrl+timePath)).GET().build();finalHttpResponse<String>timeResponse=HTTP_CLIENT.send(timeRequest,BodyHandlers.ofString());finalJsonNodetimeJson=JSON_MAPPER.readTree(timeResponse.body());finallongnetworkMs=timeJson.get("communicationTimestamps").get("receiveTimestamp").asLong();
The current network time, as understood by the queried node, is obtained using the /node/timeGET endpoint.
Nodes in the network are typically synchronized, so they return similar times.
The actual property queried is communicationTimestamps.receiveTimestamp, which represents the time at which the
request was received by the node.
This value is expressed in network time, that is, milliseconds elapsed since the Nemesis block was created.
The conversion from the current network time to UTC only requires adding the two numbers together,
taking care to use consistent units (seconds or milliseconds).
network_datetime=nemesis_datetime+datetime.timedelta(milliseconds=network_ms)print(f'\nNemesis time (UTC): {nemesis_datetime}')print(f'Network time (ms since Nemesis): {network_ms}')print(f'Network time (UTC): {network_datetime}')
constnetworkDatetime=newDate(nemesisDatetime.getTime()+Number(networkMs));console.log(`\nNemesis time (UTC): ${nemesisDatetime.toISOString()}`);console.log(`Network time (ms since Nemesis): ${networkMs}`);console.log(`Network time (UTC): ${networkDatetime.toISOString()}`);
finalInstantnetworkDatetime=nemesisDatetime.plusMillis(networkMs);System.out.printf("%nNemesis time (UTC): %s%n",nemesisDatetime);System.out.printf("Network time (ms since Nemesis): %d%n",networkMs);System.out.printf("Network time (UTC): %s%n",networkDatetime);
This tutorial makes the addition manually to show the process.
If you are using the Symbol SDK, provides a more convenient abstraction.
Using node https://whydah.symbolmain.net:3001
Fetching network properties from /network/properties
Fetching current network time from /node/time
Nemesis time (UTC): 2021-03-16T00:06:25.000Z
Network time (ms since Nemesis): 159102619442
Network time (UTC): 2026-03-31T11:16:44.442Z
Line 5 shows the Nemesis block timestamp, and always displays the same value.
Line 7 shows the current network time converted to UTC.