Skip to content
Snippets Groups Projects
Commit 9af5380e authored by Martin Lowe's avatar Martin Lowe :flag_ca: Committed by Martin Lowe
Browse files

Update listings to use date strings instead of timestamps #32


Added support for RFC 3339 date string conversion. Updated dummy script
to use moment.js to create RFC date strings.

Change-Id: I98324ddf19b20e6746eab7a576c57c67c96e8ae1
Signed-off-by: Martin Lowe's avatarMartin Lowe <martin.lowe@eclipse-foundation.org>
parent d793e7be
No related branches found
Tags v1.0-beta1
No related merge requests found
......@@ -112,6 +112,19 @@
"path-exists": "^3.0.0"
}
},
"moment": {
"version": "2.24.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
},
"moment-timezone": {
"version": "0.5.27",
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.27.tgz",
"integrity": "sha512-EIKQs7h5sAsjhPCqN6ggx6cEbs94GK050254TIJySD1bzoM5JTYDwAU1IoVOeTOL6Gm27kYJ51/uuvq1kIlrbw==",
"requires": {
"moment": ">= 2.9.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
......
......@@ -11,6 +11,7 @@
"license": "EPL-2.0",
"dependencies": {
"axios": "^0.19.0",
"moment-timezone": "^0.5.27",
"random-words": "^1.1.0",
"uuid": "^3.3.3",
"yargs": "^14.0.0"
......
......@@ -48,11 +48,11 @@ public class Listing extends NodeBase {
@SortableField(name = DatabaseFieldNames.CREATION_DATE)
@JsonbProperty(DatabaseFieldNames.CREATION_DATE)
private long creationDate;
private String creationDate;
@SortableField(name = DatabaseFieldNames.UPDATE_DATE)
@JsonbProperty(DatabaseFieldNames.UPDATE_DATE)
private long updateDate;
private String updateDate;
@JsonbProperty(DatabaseFieldNames.LICENSE_TYPE)
private String license;
private List<String> marketIds;
......@@ -224,28 +224,28 @@ public class Listing extends NodeBase {
/**
* @return the creationDate
*/
public long getCreationDate() {
public String getCreationDate() {
return creationDate;
}
/**
* @param creationDate the creationDate to set
*/
public void setCreationDate(long creationDate) {
public void setCreationDate(String creationDate) {
this.creationDate = creationDate;
}
/**
* @return the updateDate
*/
public long getUpdateDate() {
public String getUpdateDate() {
return updateDate;
}
/**
* @param updateDate the updateDate to set
*/
public void setUpdateDate(long updateDate) {
public void setUpdateDate(String updateDate) {
this.updateDate = updateDate;
}
......
......@@ -6,7 +6,6 @@
*/
package org.eclipsefoundation.marketplace.dto.codecs;
import java.util.Date;
import java.util.UUID;
import java.util.stream.Collectors;
......@@ -25,6 +24,7 @@ import org.eclipsefoundation.marketplace.dto.converters.CategoryConverter;
import org.eclipsefoundation.marketplace.dto.converters.OrganizationConverter;
import org.eclipsefoundation.marketplace.dto.converters.ListingVersionConverter;
import org.eclipsefoundation.marketplace.dto.converters.TagConverter;
import org.eclipsefoundation.marketplace.helper.DateTimeHelper;
import org.eclipsefoundation.marketplace.namespace.DatabaseFieldNames;
import com.mongodb.MongoClient;
......@@ -76,13 +76,13 @@ public class ListingCodec implements CollectibleCodec<Listing> {
doc.put(DatabaseFieldNames.TOTAL_NSTALLS, value.getInstallsTotal());
doc.put(DatabaseFieldNames.LICENSE_TYPE, value.getLicense());
doc.put(DatabaseFieldNames.LISTING_STATUS, value.getStatus());
doc.put(DatabaseFieldNames.UPDATE_DATE, new Date(value.getUpdateDate()));
doc.put(DatabaseFieldNames.CREATION_DATE, new Date(value.getCreationDate()));
doc.put(DatabaseFieldNames.UPDATE_DATE, DateTimeHelper.toRFC3339(value.getUpdateDate()));
doc.put(DatabaseFieldNames.CREATION_DATE, DateTimeHelper.toRFC3339(value.getCreationDate()));
doc.put(DatabaseFieldNames.FOUNDATION_MEMBER_FLAG, value.isFoundationMember());
doc.put(DatabaseFieldNames.CATEGORY_IDS, value.getCategoryIds());
doc.put(DatabaseFieldNames.SCREENSHOTS, value.getScreenshots());
doc.put(DatabaseFieldNames.MARKET_IDS, value.getMarketIds());
// for nested document types, use the converters to safely transform into BSON
// documents
doc.put(DatabaseFieldNames.LISTING_ORGANIZATIONS, organizationConverter.convert(value.getOrganization()));
......@@ -102,7 +102,7 @@ public class ListingCodec implements CollectibleCodec<Listing> {
public Listing decode(BsonReader reader, DecoderContext decoderContext) {
Document document = documentCodec.decode(reader, decoderContext);
Listing out = new Listing();
// for each field, get the value from the encoded object and set it in POJO
out.setId(document.getString(DatabaseFieldNames.DOCID));
out.setTitle(document.getString(DatabaseFieldNames.TITLE));
......@@ -133,9 +133,9 @@ public class ListingCodec implements CollectibleCodec<Listing> {
out.setCategories(document.getList(DatabaseFieldNames.LISTING_CATEGORIES, Document.class).stream()
.map(categoryConverter::convert).collect(Collectors.toList()));
// convert date to epoch milli
out.setCreationDate(document.getDate(DatabaseFieldNames.CREATION_DATE).toInstant().toEpochMilli());
out.setUpdateDate(document.getDate(DatabaseFieldNames.UPDATE_DATE).toInstant().toEpochMilli());
// convert date to date string
out.setCreationDate(DateTimeHelper.toRFC3339(document.getDate(DatabaseFieldNames.CREATION_DATE)));
out.setUpdateDate(DateTimeHelper.toRFC3339(document.getDate(DatabaseFieldNames.UPDATE_DATE)));
return out;
}
......
/* Copyright (c) 2019 Eclipse Foundation and others.
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License 2.0
* which is available at http://www.eclipse.org/legal/epl-v20.html,
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipsefoundation.marketplace.helper;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Central implementation for handling date time conversion in the service.
* Class uses Java8 DateTime formatters, creating an internal format that
* represents RFC 3339
*
* @author Martin Lowe
*/
public class DateTimeHelper {
private static final Logger LOGGER = LoggerFactory.getLogger(DateTimeHelper.class);
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssXXX");
/**
* Converts RFC 3339 compliant date string to date object. If non compliant
* string is passed, issue is logged and null is returned. If negative UTC
* timezone (-00:00) is passed, UTC time zone is assumed.
*
* @param dateString an RFC 3339 date string.
* @return a date object representing time in date string, or null if not in RFC
* 3339 format.
*/
public static Date toRFC3339(String dateString) {
try {
return Date.from(ZonedDateTime.parse(dateString, formatter).toInstant());
} catch (DateTimeParseException e) {
LOGGER.warn("Could not parse date from string '{}'", dateString, e);
return null;
}
}
/**
* Converts passed date to RFC 3339 compliant date string. Time is adjusted to
* be in UTC time.
*
* @param date the date object to convert to RFC 3339 format.
* @return the RFC 3339 format date string.
*/
public static String toRFC3339(Date date) {
return formatter.format(date.toInstant().atZone(ZoneId.of("UTC")));
}
// hide constructor
private DateTimeHelper() {
}
}
......@@ -26,6 +26,7 @@ const argv = require('yargs')
}).argv;
let max = argv.c;
var moment = require('moment-timezone');
const lic_types = ["EPL-2.0","EPL-1.0","GPL"];
const platforms = ["windows","macos","linux"];
const eclipseVs = ["4.6","4.7","4.8","4.9","4.10","4.11","4.12"];
......@@ -143,6 +144,8 @@ function generateJSON(id) {
"status": "draft",
"support_url": "https://jakarta.ee/about/faq",
"license_type": lic_types[Math.floor(Math.random()*lic_types.length)],
"created": moment.tz((new Date()).toISOString(), "America/Toronto").format(),
"changed": moment.tz((new Date()).toISOString(), "America/Toronto").format(),
"authors": [
{
"full_name": "Martin Lowe",
......
/* Copyright (c) 2019 Eclipse Foundation and others.
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License 2.0
* which is available at http://www.eclipse.org/legal/epl-v20.html,
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipsefoundation.marketplace.helper;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import io.quarkus.test.junit.QuarkusTest;
/**
* Test class for {@linkplain DateTimeHelper}
*
* @author Martin Lowe
*/
@QuarkusTest
public class DateTimeHelperTest {
@Test
public void validRFC3339DateStringIn() {
// Test standard time
String dateString = "1996-12-19T16:39:57-08:00";
// Timezone needs to be set as otherwise it defaults to system local offset.
TimeZone tz = TimeZone.getTimeZone(ZoneId.of("GMT-08:00"));
Calendar c = Calendar.getInstance(tz);
Date d = DateTimeHelper.toRFC3339(dateString);
c.setTime(d);
Assertions.assertEquals(1996, c.get(Calendar.YEAR));
// 0 based month
Assertions.assertEquals(11, c.get(Calendar.MONTH));
Assertions.assertEquals(19, c.get(Calendar.DATE));
Assertions.assertEquals(16, c.get(Calendar.HOUR_OF_DAY));
Assertions.assertEquals(39, c.get(Calendar.MINUTE));
Assertions.assertEquals(57, c.get(Calendar.SECOND));
Assertions.assertEquals(-TimeUnit.MILLISECONDS.convert(8, TimeUnit.HOURS),
c.get(Calendar.ZONE_OFFSET) + c.get(Calendar.DST_OFFSET));
// Test unknown offset time
String unknownOffsetDateString = "1996-12-19T16:39:57-00:00";
c = Calendar.getInstance(TimeZone.getTimeZone(ZoneId.of("UTC")));
// set calendar to actual value for easy reading
d = DateTimeHelper.toRFC3339(unknownOffsetDateString);
c.setTime(d);
System.out.println(c.toInstant().toString());
Assertions.assertEquals(1996, c.get(Calendar.YEAR));
// 0 based month
Assertions.assertEquals(11, c.get(Calendar.MONTH));
Assertions.assertEquals(19, c.get(Calendar.DATE));
Assertions.assertEquals(16, c.get(Calendar.HOUR_OF_DAY));
Assertions.assertEquals(39, c.get(Calendar.MINUTE));
Assertions.assertEquals(57, c.get(Calendar.SECOND));
Assertions.assertEquals(0, c.get(Calendar.ZONE_OFFSET) + c.get(Calendar.DST_OFFSET));
}
@Test
public void validRFC3339DateStringOut() {
// Set a time equal to "1996-12-19T16:39:57-08:00"
// Timezone needs to be set as otherwise it defaults to system local offset.
TimeZone tz = TimeZone.getTimeZone(ZoneId.of("GMT-08:00"));
// create a calendar instance to represent the given date
Calendar c = Calendar.getInstance(tz);
c.set(1996, 11, 19, 16, 39, 57);
// expect UTC time in return
String expected = "1996-12-20T00:39:57Z";
String actual = DateTimeHelper.toRFC3339(c.getTime());
Assertions.assertEquals(expected, actual);
}
@Test
public void invalidRFC3339DateStringIn() {
// test various permutations of the date string to ensure format enforcement
Assertions.assertNull(DateTimeHelper.toRFC3339("19991220"),
"Expected no returned date object for string: 19991220");
Assertions.assertNull(DateTimeHelper.toRFC3339("1996/12/20"),
"Expected no returned date object for string: 1996/12/20");
Assertions.assertNull(DateTimeHelper.toRFC3339("1996-12-20"),
"Expected no returned date object for string: 1996-12-20");
Assertions.assertNull(DateTimeHelper.toRFC3339("1996-12-20 16:39:57-08:00"),
"Expected no returned date object for string: 1996-12-20 16:39:57-08:00");
Assertions.assertNull(DateTimeHelper.toRFC3339("1996-12-20T16:39:57"),
"Expected no returned date object for string: 1996-12-20T16:39:57");
Assertions.assertNull(DateTimeHelper.toRFC3339("1996-12-20T16:39:57-0800"),
"Expected no returned date object for string: 1996-12-20T16:39:57-0800");
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment