BAEL-5666 - Create Date from Unix timestamp in Java (#12650)

* moving SpringBootPersistenceApplication class to its own package

* from com.baeldung to com.baeldung.logging to prevent it from loading
contexts from other applications.

* moving SpringBootPersistenceApplication class to its own package

* from com.baeldung to com.baeldung.logging to prevent it from loading
contexts from other applications.

* Spring Data MongoDB - Configure Connection

Ready for revision.

* fixed tests to reflect article changes

* BAEL-5657

* reverting BAEL-5657

* reverting BAEL-5657

* ready for review

* removing bael-5366

* removing bael-5366

* removing extra blank space

* bael-5666

editor review

* editor review

* long literals
* junit 5
* private constructor for utils

* junit5 assertThat
This commit is contained in:
Ulisses Lima 2022-09-16 17:31:27 -03:00 committed by GitHub
parent 171e4bd7c8
commit f3ef5a257f
13 changed files with 208 additions and 325 deletions

View File

@ -13,4 +13,4 @@ This module contains articles about date operations in Java.
- [Getting the Week Number From Any Date](https://www.baeldung.com/java-get-week-number)
- [Subtract Days from a Date in Java](https://www.baeldung.com/java-subtract-days-from-date)
- [How to Calculate “Time Ago” in Java](https://www.baeldung.com/java-calculate-time-ago)
- [[<-- Prev]](/core-java-modules/core-java-date-operations-1)
- [[<-- Prev]](/core-java-modules/core-java-date-operations-1) [[Next-->]](/core-java-modules/core-java-date-operations-3)

View File

@ -0,0 +1,6 @@
## Core Date Operations (Part 3)
This module contains articles about date operations in Java.
### Relevant Articles:
- [[<-- Prev]](/core-java-modules/core-java-date-operations-2)

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>core-java-date-operations-3</artifactId>
<version>${project.parent.version}</version>
<name>core-java-date-operations-3</name>
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung.core-java-modules</groupId>
<artifactId>core-java-modules</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependencies>
</dependencies>
<properties>
</properties>
</project>

View File

@ -0,0 +1,60 @@
package com.baeldung.unixtime;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
public class UnixTimeUtils {
private UnixTimeUtils() {
}
public static Date dateFrom(long timestamp) {
return new Date(timestamp);
}
public static Calendar calendarFrom(long timestamp) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(timestamp);
return calendar;
}
public static Instant fromNanos(long timestamp) {
long seconds = timestamp / 1_000_000_000;
long nanos = timestamp % 1_000_000_000;
return Instant.ofEpochSecond(seconds, nanos);
}
public static Instant fromTimestamp(long timestamp) {
return Instant.ofEpochMilli(millis(timestamp));
}
public static String format(Instant instant) {
LocalDateTime time = localTimeUtc(instant);
return time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
public static LocalDateTime localTimeUtc(Instant instant) {
return LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
}
private static long millis(long timestamp) {
if (timestamp >= 1E16 || timestamp <= -1E16) {
return timestamp / 1_000_000;
}
if (timestamp >= 1E14 || timestamp <= -1E14) {
return timestamp / 1_000;
}
if (timestamp >= 1E11 || timestamp <= -3E10) {
return timestamp;
}
return timestamp * 1_000;
}
}

View File

@ -0,0 +1,104 @@
package com.baeldung.unixtime;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.temporal.ChronoField;
import java.util.Calendar;
import java.util.Date;
import org.junit.jupiter.api.Test;
class UnixTimeUtilsUnitTest {
private static final String AUG_16_2022_15h25m32_Z_FORMATTED = "2022-08-16T15:25:32";
private static final long AUG_16_2022_15h25m32_Z_NANOS = 1660663532747420283L;
private static final long AUGUST = 8;
private void assertInstantFieldsMatch(LocalDateTime time) {
assertEquals(AUGUST, time.get(ChronoField.MONTH_OF_YEAR));
assertEquals(16, time.get(ChronoField.DAY_OF_MONTH));
assertEquals(2022, time.get(ChronoField.YEAR));
assertEquals(15, time.get(ChronoField.HOUR_OF_DAY));
assertEquals(25, time.get(ChronoField.MINUTE_OF_HOUR));
assertEquals(32, time.get(ChronoField.SECOND_OF_MINUTE));
}
@Test
void givenMillis_whenDateFrom_thenLocalTimeMatches() {
long millis = AUG_16_2022_15h25m32_Z_NANOS / 1000 / 1000;
Date date = UnixTimeUtils.dateFrom(millis);
LocalDateTime time = UnixTimeUtils.localTimeUtc(date.toInstant());
assertInstantFieldsMatch(time);
}
@Test
void givenMillis_whenCalendarFrom_thenLocalTimeMatches() {
long millis = AUG_16_2022_15h25m32_Z_NANOS / 1000 / 1000;
Calendar calendar = UnixTimeUtils.calendarFrom(millis);
LocalDateTime time = UnixTimeUtils.localTimeUtc(calendar.toInstant());
assertInstantFieldsMatch(time);
}
@Test
void whenInstantFromNanos_thenLocalTimeMatches() {
Instant instant = UnixTimeUtils.fromNanos(AUG_16_2022_15h25m32_Z_NANOS);
LocalDateTime time = UnixTimeUtils.localTimeUtc(instant);
assertThat(time.toString()).startsWith(AUG_16_2022_15h25m32_Z_FORMATTED);
}
@Test
void givenWrongPrecision_whenInstantFromNanos_thenUnexpectedTime() {
long microseconds = AUG_16_2022_15h25m32_Z_NANOS / 1000;
Instant instant = UnixTimeUtils.fromNanos(microseconds);
LocalDateTime time = UnixTimeUtils.localTimeUtc(instant);
assertThat(time.toString()).doesNotStartWith(AUG_16_2022_15h25m32_Z_FORMATTED);
assertEquals("1970-01-20T05:17:43.532747420", time.toString());
}
@Test
void givenNanos_whenInstantFromTimestamp_thenLocalTimeMatches() {
Instant instant = UnixTimeUtils.fromTimestamp(AUG_16_2022_15h25m32_Z_NANOS);
LocalDateTime time = UnixTimeUtils.localTimeUtc(instant);
assertInstantFieldsMatch(time);
}
@Test
void givenMicroseconds_whenInstantFromTimestamp_thenLocalTimeMatches() {
long microseconds = AUG_16_2022_15h25m32_Z_NANOS / 1000;
Instant instant = UnixTimeUtils.fromTimestamp(microseconds);
LocalDateTime time = UnixTimeUtils.localTimeUtc(instant);
assertInstantFieldsMatch(time);
}
@Test
void givenMillis_whenInstantFromTimestamp_thenLocalTimeMatches() {
long millis = AUG_16_2022_15h25m32_Z_NANOS / 1000 / 1000;
Instant instant = UnixTimeUtils.fromTimestamp(millis);
LocalDateTime time = UnixTimeUtils.localTimeUtc(instant);
assertInstantFieldsMatch(time);
}
@Test
void givenSeconds_whenInstantFromTimestamp_thenLocalTimeMatches() {
long seconds = AUG_16_2022_15h25m32_Z_NANOS / 1000 / 1000 / 1000;
Instant instant = UnixTimeUtils.fromTimestamp(seconds);
LocalDateTime time = UnixTimeUtils.localTimeUtc(instant);
assertInstantFieldsMatch(time);
}
}

View File

@ -55,6 +55,7 @@
<module>core-java-console</module>
<module>core-java-8-datetime-2</module>
<module>core-java-date-operations-2</module>
<module>core-java-date-operations-3</module>
<module>core-java-8-datetime</module>
<module>core-java-exceptions</module>
<module>core-java-exceptions-2</module>

View File

@ -0,0 +1,13 @@
package com.baeldung;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootPersistenceApplication {
public static void main(String ... args) {
SpringApplication.run(SpringBootPersistenceApplication.class, args);
}
}

View File

@ -1,31 +0,0 @@
package com.baeldung.boot.connection.via.builder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.mongo.MongoClientSettingsBuilderCustomizer;
import org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import com.mongodb.ConnectionString;
@EnableAutoConfiguration(exclude = EmbeddedMongoAutoConfiguration.class)
@EnableMongoRepositories(basePackages = { "com.baeldung.boot.connection.base" })
@SpringBootApplication(scanBasePackages = { "com.baeldung.boot.connection.base" })
public class SpringMongoConnectionViaBuilderApp {
public static void main(String... args) {
SpringApplicationBuilder app = new SpringApplicationBuilder(SpringMongoConnectionViaBuilderApp.class);
app.web(WebApplicationType.NONE);
app.run(args);
}
@Bean
public MongoClientSettingsBuilderCustomizer customizer(@Value("${custom.uri}") String uri) {
ConnectionString connection = new ConnectionString(uri);
return settings -> settings.applyConnectionString(connection);
}
}

View File

@ -1,46 +0,0 @@
package com.baeldung.boot.connection.via.client;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.data.mongodb.config.AbstractMongoClientConfiguration;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import com.mongodb.client.ListDatabasesIterable;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
@EnableAutoConfiguration(exclude = EmbeddedMongoAutoConfiguration.class)
@EnableMongoRepositories(basePackages = { "com.baeldung.boot.connection.base" })
@SpringBootApplication(scanBasePackages = { "com.baeldung.boot.connection.base" })
public class SpringMongoConnectionViaClientApp extends AbstractMongoClientConfiguration {
public static void main(String... args) {
SpringApplicationBuilder app = new SpringApplicationBuilder(SpringMongoConnectionViaClientApp.class);
app.web(WebApplicationType.NONE);
app.run(args);
}
@Value("${spring.data.mongodb.uri}")
private String uri;
@Value("${spring.data.mongodb.database}")
private String db;
@Override
public MongoClient mongoClient() {
MongoClient client = MongoClients.create(uri);
ListDatabasesIterable<Document> databases = client.listDatabases();
databases.forEach(System.out::println);
return client;
}
@Override
protected String getDatabaseName() {
return db;
}
}

View File

@ -1,40 +0,0 @@
package com.baeldung.boot.connection.via.factory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.data.mongodb.core.MongoClientFactoryBean;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import com.mongodb.ConnectionString;
import com.mongodb.client.MongoClient;
@EnableAutoConfiguration(exclude = EmbeddedMongoAutoConfiguration.class)
@EnableMongoRepositories(basePackages = { "com.baeldung.boot.connection.base" })
@SpringBootApplication(scanBasePackages = { "com.baeldung.boot.connection.base" })
public class SpringMongoConnectionViaFactoryApp {
public static void main(String... args) {
SpringApplicationBuilder app = new SpringApplicationBuilder(SpringMongoConnectionViaFactoryApp.class);
app.web(WebApplicationType.NONE);
app.run(args);
}
@Bean
public MongoClientFactoryBean mongo(@Value("${custom.uri}") String uri) throws Exception {
MongoClientFactoryBean mongo = new MongoClientFactoryBean();
ConnectionString conn = new ConnectionString(uri);
mongo.setConnectionString(conn);
mongo.setSingleton(false);
MongoClient client = mongo.getObject();
client.listDatabaseNames()
.forEach(System.out::println);
return mongo;
}
}

View File

@ -1,22 +0,0 @@
package com.baeldung.boot.connection.via.properties;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
@PropertySource("classpath:connection.via.properties/app.properties")
@EnableAutoConfiguration(exclude = EmbeddedMongoAutoConfiguration.class)
@EnableMongoRepositories(basePackages = { "com.baeldung.boot.connection.base" })
@SpringBootApplication(scanBasePackages = { "com.baeldung.boot.connection.base" })
public class SpringMongoConnectionViaPropertiesApp {
public static void main(String... args) {
SpringApplicationBuilder app = new SpringApplicationBuilder(SpringMongoConnectionViaPropertiesApp.class);
app.web(WebApplicationType.NONE);
app.run(args);
}
}

View File

@ -1,5 +0,0 @@
spring.data.mongodb.database=baeldung
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.username=admin
spring.data.mongodb.password=password

View File

@ -1,180 +0,0 @@
package com.baeldung.boot.connection.via.tests;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import org.bson.Document;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.test.annotation.DirtiesContext;
import com.baeldung.boot.connection.via.builder.SpringMongoConnectionViaBuilderApp;
import com.baeldung.boot.connection.via.client.SpringMongoConnectionViaClientApp;
import com.baeldung.boot.connection.via.factory.SpringMongoConnectionViaFactoryApp;
import com.baeldung.boot.connection.via.properties.SpringMongoConnectionViaPropertiesApp;
@DirtiesContext
public class MongoConnectionApplicationLiveTest {
private static final String HOST = "localhost";
private static final String PORT = "27017";
private static final String DB = "baeldung";
private static final String USER = "admin";
private static final String PASS = "password";
private void assertInsertSucceeds(ConfigurableApplicationContext context) {
String name = "A";
MongoTemplate mongo = context.getBean(MongoTemplate.class);
Document doc = Document.parse("{\"name\":\"" + name + "\"}");
Document inserted = mongo.insert(doc, "items");
assertNotNull(inserted.get("_id"));
assertEquals(inserted.get("name"), name);
}
@Before
public void clearSystemProperties() {
System.clearProperty("spring.data.mongodb.host");
System.clearProperty("spring.data.mongodb.port");
System.clearProperty("spring.data.mongodb.database");
System.clearProperty("spring.data.mongodb.username");
System.clearProperty("spring.data.mongodb.password");
System.clearProperty("spring.data.mongodb.uri");
}
@Test
public void whenPropertiesConfig_thenInsertSucceeds() {
SpringApplicationBuilder app = new SpringApplicationBuilder(SpringMongoConnectionViaPropertiesApp.class);
app.web(WebApplicationType.NONE)
.run();
assertInsertSucceeds(app.context());
}
@Test
public void whenSystemConfig_thenInsertSucceeds() {
System.setProperty("spring.data.mongodb.host", HOST);
System.setProperty("spring.data.mongodb.port", PORT);
System.setProperty("spring.data.mongodb.database", DB);
System.setProperty("spring.data.mongodb.username", USER);
System.setProperty("spring.data.mongodb.password", PASS);
SpringApplicationBuilder app = new SpringApplicationBuilder(SpringMongoConnectionViaPropertiesApp.class);
app.web(WebApplicationType.NONE)
.run();
assertInsertSucceeds(app.context());
}
@Test
public void givenPrecedence_whenSystemConfig_thenInsertSucceeds() {
System.setProperty("spring.data.mongodb.host", HOST);
System.setProperty("spring.data.mongodb.port", PORT);
System.setProperty("spring.data.mongodb.database", DB);
System.setProperty("spring.data.mongodb.username", USER);
System.setProperty("spring.data.mongodb.password", PASS);
SpringApplicationBuilder app = new SpringApplicationBuilder(SpringMongoConnectionViaPropertiesApp.class)
.properties(
"spring.data.mongodb.host=oldValue",
"spring.data.mongodb.port=oldValue",
"spring.data.mongodb.database=oldValue",
"spring.data.mongodb.username=oldValue",
"spring.data.mongodb.password=oldValue"
);
app.web(WebApplicationType.NONE)
.run();
assertInsertSucceeds(app.context());
}
@Test
public void givenPrecedence_whenApplicationArgs_thenInsertSucceeds() {
System.setProperty("spring.data.mongodb.host", "incorrect");
System.setProperty("spring.data.mongodb.port", "incorrect");
System.setProperty("spring.data.mongodb.database", "incorrect");
System.setProperty("spring.data.mongodb.username", "incorrect");
System.setProperty("spring.data.mongodb.password", "incorrect");
SpringApplicationBuilder app = new SpringApplicationBuilder(SpringMongoConnectionViaPropertiesApp.class);
app.web(WebApplicationType.NONE)
.run(
"--spring.data.mongodb.host=" + HOST,
"--spring.data.mongodb.port=" + PORT,
"--spring.data.mongodb.database=" + DB,
"--spring.data.mongodb.username=" + USER,
"--spring.data.mongodb.password=" + PASS
);
assertInsertSucceeds(app.context());
}
@Test
public void givenConnectionUri_whenAlsoIncludingIndividualParameters_thenInvalidConfig() {
System.setProperty(
"spring.data.mongodb.uri",
"mongodb://" + USER + ":" + PASS + "@" + HOST + ":" + PORT + "/" + DB
);
SpringApplicationBuilder app = new SpringApplicationBuilder(SpringMongoConnectionViaPropertiesApp.class)
.web(WebApplicationType.NONE)
.properties(
"spring.data.mongodb.host=" + HOST,
"spring.data.mongodb.port=" + PORT,
"spring.data.mongodb.username=" + USER,
"spring.data.mongodb.password=" + PASS
);
BeanCreationException e = assertThrows(BeanCreationException.class, () -> {
app.run();
});
Throwable rootCause = e.getRootCause();
assertTrue(rootCause instanceof IllegalStateException);
assertThat(rootCause.getMessage()
.contains("Invalid mongo configuration, either uri or host/port/credentials/replicaSet must be specified"));
}
@Test
public void whenClientConfig_thenInsertSucceeds() {
SpringApplicationBuilder app = new SpringApplicationBuilder(SpringMongoConnectionViaClientApp.class);
app.web(WebApplicationType.NONE)
.run(
"--spring.data.mongodb.uri=mongodb://" + USER + ":" + PASS + "@" + HOST + ":" + PORT + "/" + DB,
"--spring.data.mongodb.database=" + DB
);
assertInsertSucceeds(app.context());
}
@Test
public void whenFactoryConfig_thenInsertSucceeds() {
SpringApplicationBuilder app = new SpringApplicationBuilder(SpringMongoConnectionViaFactoryApp.class);
app.web(WebApplicationType.NONE)
.run(
"--custom.uri=mongodb://" + USER + ":" + PASS + "@" + HOST + ":" + PORT + "/" + DB
);
assertInsertSucceeds(app.context());
}
@Test
public void whenBuilderConfig_thenInsertSucceeds() {
SpringApplicationBuilder app = new SpringApplicationBuilder(SpringMongoConnectionViaBuilderApp.class);
app.web(WebApplicationType.NONE)
.run(
"--custom.uri=mongodb://" + USER + ":" + PASS + "@" + HOST + ":" + PORT + "/" + DB
);
assertInsertSucceeds(app.context());
}
}