Skip to content

Timezone fix in validateInternalTimestampIsNotOutdated()#12355

Open
landreev wants to merge 2 commits intodevelopfrom
12354-timezone-bug
Open

Timezone fix in validateInternalTimestampIsNotOutdated()#12355
landreev wants to merge 2 commits intodevelopfrom
12354-timezone-bug

Conversation

@landreev
Copy link
Copy Markdown
Contributor

@landreev landreev commented Apr 22, 2026

What this PR does / why we need it:

In the intended API workflow the client using the sourceLastUpdateTime parameter would be reusing the timestamps obtained from the output of other Dataverse APIs, like /versions and /files, where they are always reported in UTC, ISO 8601-formatted. (with the "Z", for ex.: 2026-04-22T14:30:00Z; regardless of where the server lives).
This format is specified as required in the guides.

However, the scheme appears to work only if the server happens to live in GMT and save the timestamps in the database that are already UTC.
That happens to be the case with Jenkins, beta, qa and docker instances (and that's how the bug stayed unnoticed for a year). But it becomes a problem on servers that use different time zones. Such as our "real" servers, demo.dataverse.org and dataverse.harvard.edu that live in US Eastern. (It was confirmed that file metadata could not be updated in the SPA on demo because of this)

Which issue(s) this PR closes:

Special notes for your reviewer:

The simplest, minimalist fix would be 3 characters total: change yyyy-MM-dd'T'HH:mm:ss'Z' to yyyy-MM-dd'T'HH:mm:ssX. i.e., from "ignore the literal 'Z'" to "parse ISO 8601 time zone", which recognizes "Z" as "+0000".
But I added some comments and rewrote a few sentences that describe the parameter in the API guide.

Branch rebased to squash the commits.

Suggestions on how to test this:

Testing is straightforward, you just need a Dataverse instance operating in a non-GMT time zone. If you have a working Payara etc. setup installed locally on your computer, then you are all set. Unless you live in London, etc.

If you are testing with a Docker environment, you should be able to configure it to run in US Eastern by adding this to your docker-compose-dev.yml:

--- docker-compose-dev.yml
+++ docker-compose-dev-us-east.yml
@@ -9,6 +9,7 @@
     restart: on-failure
     user: payara
     environment:
+      TZ: America/New_York
       DATAVERSE_DB_HOST: postgres
       DATAVERSE_DB_PASSWORD: secret
       DATAVERSE_DB_USER: ${DATAVERSE_DB_USER}
@@ -113,6 +114,7 @@
     image: postgres:${POSTGRES_VERSION}
     restart: on-failure
     environment:
+      - TZ=America/New_York
       - POSTGRES_USER=${DATAVERSE_DB_USER}
       - POSTGRES_PASSWORD=secret
     ports:

Rebuild your Docker env. completely from scratch.

I recommend to make sure to reproduce the actual bug in 6.10.1 and current develop; as there were some conflicting reports on how easy that was.
It should be possible to test the bug, and the fix by simply making the 2 API calls involved directly. The best way however is probably to run one of the RestAssured tests that cover the functionality, for example

mvn test -Dtest=FilesIT#testUpdateWithEmptyFieldsAndVersionCheck

The failure would look something like this in the output:

            "directoryLabel": "data/subdir1",
            "lastUpdateTime": "2026-04-22T19:54:20Z",
            "fileAccessRequest": true
        }
    }
}
{
    "status": "ERROR",
    "message": "Internal version timestamp 2026-04-22T19:54:20Z is outdated"
}
[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 13.06 s <<< FAILURE! -- in edu.harvard.iq.dataverse.api.FilesIT
[ERROR] edu.harvard.iq.dataverse.api.FilesIT.testUpdateWithEmptyFieldsAndVersionCheck -- Time elapsed: 10.40 s <<< FAILURE!

Note that the time stamp described in the API error as "outdated" appears strikingly identical to the actual lastUpdateTime in the output of the GET API right above.

Does this PR introduce a user interface change? If mockups are available, please link/include them here:

Is there a release notes update needed for this change?:

Additional documentation:

@github-actions github-actions Bot added FY26 Sprint 22 FY26 Sprint 22 (2026-04-22 - 2026-05-06) Original size: 3 labels Apr 22, 2026
@coveralls
Copy link
Copy Markdown

coveralls commented Apr 22, 2026

Coverage Status

coverage: 24.886% (-0.001%) from 24.887% — 12354-timezone-bug into develop

@github-actions

This comment has been minimized.

@landreev
Copy link
Copy Markdown
Contributor Author

It's still working with the server living on GMT (it just passed Jenkins tests).
I'll clean it up and also the language in the API guide about these timestamps, then move it into ready-for-review.

@landreev
Copy link
Copy Markdown
Contributor Author

The simplest fix would be just this:

--- a/src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java
+++ b/src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java
@@ -488,7 +488,7 @@ public abstract class AbstractApiBean {
     }
 
     protected void validateInternalTimestampIsNotOutdated(DvObject dvObject, String sourceLastUpdateTime) throws WrappedResponse {
-        Date date = sourceLastUpdateTime != null ? DateUtil.parseDate(sourceLastUpdateTime, "yyyy-MM-dd'T'HH:mm:ss'Z'") : null;
+        Date date = sourceLastUpdateTime != null ? DateUtil.parseDate(sourceLastUpdateTime, "yyyy-MM-dd'T'HH:mm:ssX") : null;
         if (date == null) {
             throw new WrappedResponse(
                     badRequest(BundleUtil.getStringFromBundle("jsonparser.error.parsing.date", Collections.singletonList(sourceLastUpdateTime)))

... no need really to mess with the incoming ISO 8601 string.

@github-actions

This comment has been minimized.

1 similar comment
@github-actions

This comment has been minimized.

…otOutdated(). #12354

A slightly cleaner fix #12354

Refined (and, maybe even improved?) the language in the guides documenting the sourceLastUpdateTime parameter. #12354

a typo #12354
@landreev landreev force-pushed the 12354-timezone-bug branch from be405f7 to 0d5883d Compare April 24, 2026 21:41
@landreev landreev self-assigned this Apr 24, 2026
@landreev landreev marked this pull request as ready for review April 24, 2026 21:47
@landreev landreev added Size: 10 A percentage of a sprint. 7 hours. and removed Original size: 3 labels Apr 24, 2026
@landreev landreev moved this to Ready for Review ⏩ in IQSS Dataverse Project Apr 24, 2026
@landreev landreev requested a review from stevenwinship April 24, 2026 21:48
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

1 similar comment
@github-actions
Copy link
Copy Markdown

📦 Pushed preview images as

ghcr.io/gdcc/dataverse:12354-timezone-bug
ghcr.io/gdcc/configbaker:12354-timezone-bug

🚢 See on GHCR. Use by referencing with full name as printed above, mind the registry name.

@landreev landreev removed their assignment Apr 25, 2026
@stevenwinship stevenwinship moved this from Ready for Review ⏩ to In Review 🔎 in IQSS Dataverse Project Apr 27, 2026
@stevenwinship stevenwinship self-assigned this Apr 27, 2026
@github-project-automation github-project-automation Bot moved this from In Review 🔎 to Ready for QA ⏩ in IQSS Dataverse Project Apr 27, 2026
@stevenwinship stevenwinship removed their assignment Apr 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

FY26 Sprint 22 FY26 Sprint 22 (2026-04-22 - 2026-05-06) Size: 10 A percentage of a sprint. 7 hours.

Projects

Status: Ready for QA ⏩

Development

Successfully merging this pull request may close these issues.

Fix a bug in validateInternalTimestampIsNotOutdated()

3 participants