Reputation: 6963
I am using the UTC timezone and the time in my application to get data. In the application, wherever the user can get the UTC time and used for getting the data. I used this method to get the UTC time.
String format = "yyyy-MM-dd HH:mm:ss";
final SimpleDateFormat sdf = new SimpleDateFormat(format);
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
String utcTime = sdf.format(new Date());
The application is working fine. But it is converting the system time to UTC time. The problem is that sometimes the user can change the time to the wrong time. So the data is not coming.
Case for the above issue is:
For example the current date time in India is Thursday, 26 July 2012, 14:27:56, time zone Kolkata. Then the time, Pacific time zone, should be Thursday, 26 July 2012, 01:59:30 PDT.
But the user changed his device time from 14:27:56 to 13:27:56, so the converted UTC time will be Thursday, 26 July 2012, 00:59:30 PDT. At this point my app is not able to get the date because of the one-hour difference.
I don't want to use date, Calendar classes for Java and I don't want to use the device time. How can I get the UTC time directly, without involving the device's time, date. Is there any open-source API for that?
Thanks in advance.
Upvotes: 9
Views: 25417
Reputation: 1498
For android, if you tried to connect to the Internet from the main thread the app will crash, so I edited to code to work correctly on android
import android.os.AsyncTask;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class NTPUTCTime {
private static final String TAG = "SntpClient";
private static final int RECEIVE_TIME_OFFSET = 32;
private static final int TRANSMIT_TIME_OFFSET = 40;
private static final int NTP_PACKET_SIZE = 48;
private static final int NTP_PORT = 123;
private static final int NTP_MODE_CLIENT = 3;
private static final int NTP_VERSION = 3;
// Number of seconds between Jan 1, 1900 and Jan 1, 1970
// 70 years plus 17 leap days
private static final long OFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L;
private long mNtpTime;
public boolean requestTime() {
try {
new AsyncTask<Void, Void, Boolean>() {
@Override
protected Boolean doInBackground(Void... voids) {
try {
DatagramSocket socket = new DatagramSocket();
socket.setSoTimeout(1000);
InetAddress address = InetAddress.getByName("pool.ntp.org");
byte[] buffer = new byte[NTP_PACKET_SIZE];
DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, NTP_PORT);
buffer[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3);
writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET);
socket.send(request);
// read the response
DatagramPacket response = new DatagramPacket(buffer, buffer.length);
socket.receive(response);
socket.close();
mNtpTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET);
} catch (Exception e) {
// if (Config.LOGD) Log.d(TAG, "request time failed: " + e);
e.printStackTrace();
return false;
}
return true;
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR).get();
} catch (Exception e) {
// if (Config.LOGD) Log.d(TAG, "request time failed: " + e);
e.printStackTrace();
return false;
}
return true;
}
public long getNtpTime() {
return mNtpTime;
}
/**
* Reads an unsigned 32 bit big endian number from the given offset in the buffer.
*/
private long read32(byte[] buffer, int offset) {
byte b0 = buffer[offset];
byte b1 = buffer[offset + 1];
byte b2 = buffer[offset + 2];
byte b3 = buffer[offset + 3];
// convert signed bytes to unsigned values
int i0 = ((b0 & 0x80) == 0x80 ? (b0 & 0x7F) + 0x80 : b0);
int i1 = ((b1 & 0x80) == 0x80 ? (b1 & 0x7F) + 0x80 : b1);
int i2 = ((b2 & 0x80) == 0x80 ? (b2 & 0x7F) + 0x80 : b2);
int i3 = ((b3 & 0x80) == 0x80 ? (b3 & 0x7F) + 0x80 : b3);
return ((long) i0 << 24) + ((long) i1 << 16) + ((long) i2 << 8) + (long) i3;
}
/**
* Reads the NTP time stamp at the given offset in the buffer and returns
* it as a system time (milliseconds since January 1, 1970).
*/
private long readTimeStamp(byte[] buffer, int offset) {
long seconds = read32(buffer, offset);
long fraction = read32(buffer, offset + 4);
return ((seconds - OFFSET_1900_TO_1970) * 1000) + ((fraction * 1000L) / 0x100000000L);
}
/**
* Writes 0 as NTP starttime stamp in the buffer. --> Then NTP returns Time OFFSET since 1900
*/
private void writeTimeStamp(byte[] buffer, int offset) {
int ofs = offset++;
for (int i = ofs; i < (ofs + 8); i++)
buffer[i] = (byte) (0);
}
}
Upvotes: 0
Reputation: 47
class GetUTCTime : AppCompatActivity() {
private val OUTPUT_DATE_FORMATE = "dd-MM-yyyy - hh:mm a"
internal lateinit var textView : TextView
val utcTime: String
get() {
LongOperation().execute("")
return ""
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_get_utctime)
// Log.d("UTC", "onCreate: "+ getUTCTime());
textView = findViewById(R.id.dateTime)
findViewById<View>(R.id.fetchButton).setOnClickListener {
utcTime
textView.text = "Fetching..."
}
}
private inner class LongOperation : AsyncTask<String, Void, Long>() {
override fun doInBackground(vararg params: String): Long? {
var nowAsPerDeviceTimeZone: Long = 0
try {
val sntpClient = SntpClient()
if (sntpClient.requestTime("ntp.ubuntu.com", 30000)) {
nowAsPerDeviceTimeZone = sntpClient.ntpTime
}
Thread.sleep(1000)
} catch (e: InterruptedException) {
Thread.interrupted()
}
return nowAsPerDeviceTimeZone
}
override fun onPostExecute(nowAsPerDeviceTimeZone: Long?) {
// might want to change "executed" for the returned string passed
// into onPostExecute() but that is upto you
Log.d("GMT", "getUTCTime:0 " + Date(nowAsPerDeviceTimeZone!!))
textView.text = Date(nowAsPerDeviceTimeZone).toString()
// Calendar cal = Calendar.getInstance();
// TimeZone timeZoneInDevice = cal.getTimeZone();
// int differentialOfTimeZones = timeZoneInDevice.getOffset(System.currentTimeMillis());
// nowAsPerDeviceTimeZone -= differentialOfTimeZones;
//
//
//
//
//
// Log.d("GMT", "getUTCTime:1 "+ new Date(nowAsPerDeviceTimeZone).toString());
}
override fun onPreExecute() {}
override fun onProgressUpdate(vararg values: Void) {}
}
}
Upvotes: -2
Reputation: 5381
UTC Time over SntpClient above don't work if the the Sytem time changed e.g. manually for 8 hours. Because it using System.currentTimeMillis wich returns the false value!!!
// get current time and write it to the request packet
long requestTime = System.currentTimeMillis();
long requestTicks = SystemClock.elapsedRealtime();
Better use this Class to get the right UTC Time from NTP Server:
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
class NTP_UTC_Time
{
private static final String TAG = "SntpClient";
private static final int RECEIVE_TIME_OFFSET = 32;
private static final int TRANSMIT_TIME_OFFSET = 40;
private static final int NTP_PACKET_SIZE = 48;
private static final int NTP_PORT = 123;
private static final int NTP_MODE_CLIENT = 3;
private static final int NTP_VERSION = 3;
// Number of seconds between Jan 1, 1900 and Jan 1, 1970
// 70 years plus 17 leap days
private static final long OFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L;
private long mNtpTime;
public boolean requestTime(String host, int timeout) {
try {
DatagramSocket socket = new DatagramSocket();
socket.setSoTimeout(timeout);
InetAddress address = InetAddress.getByName(host);
byte[] buffer = new byte[NTP_PACKET_SIZE];
DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, NTP_PORT);
buffer[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3);
writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET);
socket.send(request);
// read the response
DatagramPacket response = new DatagramPacket(buffer, buffer.length);
socket.receive(response);
socket.close();
mNtpTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET);
} catch (Exception e) {
// if (Config.LOGD) Log.d(TAG, "request time failed: " + e);
return false;
}
return true;
}
public long getNtpTime() {
return mNtpTime;
}
/**
* Reads an unsigned 32 bit big endian number from the given offset in the buffer.
*/
private long read32(byte[] buffer, int offset) {
byte b0 = buffer[offset];
byte b1 = buffer[offset+1];
byte b2 = buffer[offset+2];
byte b3 = buffer[offset+3];
// convert signed bytes to unsigned values
int i0 = ((b0 & 0x80) == 0x80 ? (b0 & 0x7F) + 0x80 : b0);
int i1 = ((b1 & 0x80) == 0x80 ? (b1 & 0x7F) + 0x80 : b1);
int i2 = ((b2 & 0x80) == 0x80 ? (b2 & 0x7F) + 0x80 : b2);
int i3 = ((b3 & 0x80) == 0x80 ? (b3 & 0x7F) + 0x80 : b3);
return ((long)i0 << 24) + ((long)i1 << 16) + ((long)i2 << 8) + (long)i3;
}
/**
* Reads the NTP time stamp at the given offset in the buffer and returns
* it as a system time (milliseconds since January 1, 1970).
*/
private long readTimeStamp(byte[] buffer, int offset) {
long seconds = read32(buffer, offset);
long fraction = read32(buffer, offset + 4);
return ((seconds - OFFSET_1900_TO_1970) * 1000) + ((fraction * 1000L) / 0x100000000L);
}
/**
* Writes 0 as NTP starttime stamp in the buffer. --> Then NTP returns Time OFFSET since 1900
*/
private void writeTimeStamp(byte[] buffer, int offset) {
int ofs = offset++;
for (int i=ofs;i<(ofs+8);i++)
buffer[i] = (byte)(0);
}
}
And use it with:
long now = 0;
NTP_UTC_Time client = new NTP_UTC_Time();
if (client.requestTime("pool.ntp.org", 2000)) {
now = client.getNtpTime();
}
If you need UTC Time "now" as DateTimeString use function:
private String get_UTC_Datetime_from_timestamp(long timeStamp){
try{
Calendar cal = Calendar.getInstance();
TimeZone tz = cal.getTimeZone();
int tzt = tz.getOffset(System.currentTimeMillis());
timeStamp -= tzt;
// DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",Locale.getDefault());
DateFormat sdf = new SimpleDateFormat();
Date netDate = (new Date(timeStamp));
return sdf.format(netDate);
}
catch(Exception ex){
return "";
}
}
and use it with:
String UTC_DateTime = get_UTC_Datetime_from_timestamp(now);
Upvotes: 6
Reputation: 520
I think you must implement a Sntp Client and access NTP to get network time. My code:
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Date;
public class GetTime {
public static void main(String[] args) {
SntpClient client = new SntpClient();
if (client.requestTime("pool.ntp.org", 30000)) {
long now = client.getNtpTime() + System.nanoTime() / 1000
- client.getNtpTimeReference();
Date current = new Date(now);
System.out.println(current.toString());
}
}
}
class SntpClient {
private static final int ORIGINATE_TIME_OFFSET = 24;
private static final int RECEIVE_TIME_OFFSET = 32;
private static final int TRANSMIT_TIME_OFFSET = 40;
private static final int NTP_PACKET_SIZE = 48;
private static final int NTP_PORT = 123;
private static final int NTP_MODE_CLIENT = 3;
private static final int NTP_VERSION = 3;
// Number of seconds between Jan 1, 1900 and Jan 1, 1970
// 70 years plus 17 leap days
private static final long OFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L;
// system time computed from NTP server response
private long mNtpTime;
// value of SystemClock.elapsedRealtime() corresponding to mNtpTime
private long mNtpTimeReference;
// round trip time in milliseconds
private long mRoundTripTime;
/**
* Sends an SNTP request to the given host and processes the response.
*
* @param host
* host name of the server.
* @param timeout
* network timeout in milliseconds.
* @return true if the transaction was successful.
*/
public boolean requestTime(String host, int timeout) {
try {
DatagramSocket socket = new DatagramSocket();
socket.setSoTimeout(timeout);
InetAddress address = InetAddress.getByName(host);
byte[] buffer = new byte[NTP_PACKET_SIZE];
DatagramPacket request = new DatagramPacket(buffer, buffer.length,
address, NTP_PORT);
// set mode = 3 (client) and version = 3
// mode is in low 3 bits of first byte
// version is in bits 3-5 of first byte
buffer[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3);
// get current time and write it to the request packet
long requestTime = System.currentTimeMillis();
long requestTicks = System.nanoTime() / 1000;
writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET, requestTime);
socket.send(request);
// read the response
DatagramPacket response = new DatagramPacket(buffer, buffer.length);
socket.receive(response);
long responseTicks = System.nanoTime() / 1000;
long responseTime = requestTime + (responseTicks - requestTicks);
socket.close();
// extract the results
long originateTime = readTimeStamp(buffer, ORIGINATE_TIME_OFFSET);
long receiveTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET);
long transmitTime = readTimeStamp(buffer, TRANSMIT_TIME_OFFSET);
long roundTripTime = responseTicks - requestTicks
- (transmitTime - receiveTime);
// receiveTime = originateTime + transit + skew
// responseTime = transmitTime + transit - skew
// clockOffset = ((receiveTime - originateTime) + (transmitTime -
// responseTime))/2
// = ((originateTime + transit + skew - originateTime) +
// (transmitTime - (transmitTime + transit - skew)))/2
// = ((transit + skew) + (transmitTime - transmitTime - transit +
// skew))/2
// = (transit + skew - transit + skew)/2
// = (2 * skew)/2 = skew
long clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime)) / 2;
// if (Config.LOGD) Log.d(TAG, "round trip: " + roundTripTime +
// " ms");
// if (Config.LOGD) Log.d(TAG, "clock offset: " + clockOffset +
// " ms");
// save our results - use the times on this side of the network
// latency
// (response rather than request time)
mNtpTime = responseTime + clockOffset;
mNtpTimeReference = responseTicks;
mRoundTripTime = roundTripTime;
} catch (Exception e) {
return false;
}
return true;
}
/**
* Returns the time computed from the NTP transaction.
*
* @return time value computed from NTP server response.
*/
public long getNtpTime() {
return mNtpTime;
}
/**
* Returns the reference clock value (value of
* SystemClock.elapsedRealtime()) corresponding to the NTP time.
*
* @return reference clock corresponding to the NTP time.
*/
public long getNtpTimeReference() {
return mNtpTimeReference;
}
/**
* Returns the round trip time of the NTP transaction
*
* @return round trip time in milliseconds.
*/
public long getRoundTripTime() {
return mRoundTripTime;
}
/**
* Reads an unsigned 32 bit big endian number from the given offset in the
* buffer.
*/
private long read32(byte[] buffer, int offset) {
byte b0 = buffer[offset];
byte b1 = buffer[offset + 1];
byte b2 = buffer[offset + 2];
byte b3 = buffer[offset + 3];
// convert signed bytes to unsigned values
int i0 = ((b0 & 0x80) == 0x80 ? (b0 & 0x7F) + 0x80 : b0);
int i1 = ((b1 & 0x80) == 0x80 ? (b1 & 0x7F) + 0x80 : b1);
int i2 = ((b2 & 0x80) == 0x80 ? (b2 & 0x7F) + 0x80 : b2);
int i3 = ((b3 & 0x80) == 0x80 ? (b3 & 0x7F) + 0x80 : b3);
return ((long) i0 << 24) + ((long) i1 << 16) + ((long) i2 << 8)
+ (long) i3;
}
/**
* Reads the NTP time stamp at the given offset in the buffer and returns it
* as a system time (milliseconds since January 1, 1970).
*/
private long readTimeStamp(byte[] buffer, int offset) {
long seconds = read32(buffer, offset);
long fraction = read32(buffer, offset + 4);
return ((seconds - OFFSET_1900_TO_1970) * 1000)
+ ((fraction * 1000L) / 0x100000000L);
}
/**
* Writes system time (milliseconds since January 1, 1970) as an NTP time
* stamp at the given offset in the buffer.
*/
private void writeTimeStamp(byte[] buffer, int offset, long time) {
long seconds = time / 1000L;
long milliseconds = time - seconds * 1000L;
seconds += OFFSET_1900_TO_1970;
// write seconds in big endian format
buffer[offset++] = (byte) (seconds >> 24);
buffer[offset++] = (byte) (seconds >> 16);
buffer[offset++] = (byte) (seconds >> 8);
buffer[offset++] = (byte) (seconds >> 0);
long fraction = milliseconds * 0x100000000L / 1000L;
// write fraction in big endian format
buffer[offset++] = (byte) (fraction >> 24);
buffer[offset++] = (byte) (fraction >> 16);
buffer[offset++] = (byte) (fraction >> 8);
// low order bits should be random data
buffer[offset++] = (byte) (Math.random() * 255.0);
}
}
Hope that can help you.
Upvotes: 4
Reputation: 12823
long dateInMillis = System.currentTimeMillis();
This will return you the number of milliseconds since January 1, 1970 00:00:00 UTC.
Then just parse it to the most suitable format you want:
String format = "yyyy-MM-dd HH:mm:ss";
final SimpleDateFormat sdf = new SimpleDateFormat(format);
String dateString = sdf.format(new Date(dateInMillis)));
Upvotes: 5
Reputation: 118
Using the free API at http://www.worldweatheronline.com/, you can perform a HTTP GET via java to get the current time in UTC (http://www.worldweatheronline.com/time-zone-api.aspx)
Upvotes: 3