Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 51 additions & 21 deletions src/java.base/unix/native/libjava/TimeZone_md.c
Original file line number Diff line number Diff line change
Expand Up @@ -352,33 +352,15 @@ getPlatformTimeZoneID()
}

static char *
mapPlatformToJavaTimezone(const char *java_home_dir, const char *tz) {
getJavaTimezoneFromPlatform(const char *tz_buf, size_t tz_len, const char *mapfilename) {
FILE *tzmapf;
char mapfilename[PATH_MAX + 1];
char line[256];
int linecount = 0;
char *tz_buf = NULL;
char *temp_tz = NULL;
char *javatz = NULL;
size_t tz_len = 0;

/* On AIX, the TZ environment variable may end with a comma
* followed by modifier fields until early AIX6.1.
* This restriction has been removed from AIX7. */

tz_buf = strdup(tz);
tz_len = strlen(tz_buf);

/* Open tzmappings file, with buffer overrun check */
if ((strlen(java_home_dir) + 15) > PATH_MAX) {
jio_fprintf(stderr, "Path %s/lib/tzmappings exceeds maximum path length\n", java_home_dir);
goto tzerr;
}
strcpy(mapfilename, java_home_dir);
strcat(mapfilename, "/lib/tzmappings");
if ((tzmapf = fopen(mapfilename, "r")) == NULL) {
jio_fprintf(stderr, "can't open %s\n", mapfilename);
goto tzerr;
return NULL;
}

while (fgets(line, sizeof(line), tzmapf) != NULL) {
Expand Down Expand Up @@ -431,10 +413,58 @@ mapPlatformToJavaTimezone(const char *java_home_dir, const char *tz) {
break;
}
}

(void) fclose(tzmapf);
return javatz;
}

static char *
mapPlatformToJavaTimezone(const char *java_home_dir, const char *tz) {
char mapfilename[PATH_MAX + 1];
char *tz_buf = NULL;
char *javatz = NULL;
char *temp_tz = NULL;
size_t tz_len = 0;

/* On AIX, the TZ environment variable may end with a comma
* followed by modifier fields until early AIX6.1.
* This restriction has been removed from AIX7. */

tz_buf = strdup(tz);
if (tz_buf == NULL) {
jio_fprintf(stderr, "Failed to allocate timezone buffer\n");
goto tzerr;
}
tz_len = strlen(tz_buf);

/* Open tzmappings file, with buffer overrun check */
if ((strlen(java_home_dir) + 15) > PATH_MAX) {
jio_fprintf(stderr, "Path %s/lib/tzmappings exceeds maximum path length\n", java_home_dir);
goto tzerr;
}
strcpy(mapfilename, java_home_dir);
strcat(mapfilename, "/lib/tzmappings");

// First attempt to find the Java timezone for the full tz string
javatz = getJavaTimezoneFromPlatform(tz_buf, tz_len, mapfilename);

// If no match was found, check for timezone with truncated value
if (javatz == NULL) {
temp_tz = strchr(tz, ',');
tz_len = (temp_tz == NULL) ? strlen(tz) : temp_tz - tz;
free((void *) tz_buf);
tz_buf = (char *)malloc(tz_len + 1);
if (tz_buf == NULL) {
jio_fprintf(stderr, "Failed to allocate timezone buffer\n");
goto tzerr;
}
memcpy(tz_buf, tz, tz_len);
tz_buf[tz_len] = '\0';
javatz = getJavaTimezoneFromPlatform(tz_buf, tz_len, mapfilename);
}

tzerr:
if (tz_buf != NULL ) {
if (tz_buf != NULL) {
free((void *) tz_buf);
}

Expand Down
102 changes: 102 additions & 0 deletions test/jdk/java/util/TimeZone/AIXTzMappingTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

/* @test
* @bug 8380993
* @library /test/lib
* @summary Validates AIX timezone mapping behavior where POSIX TZ strings
* with comma-separated DST rules are truncated and mapped through tzmappings
* to the expected IANA timezone IDs.
* @requires os.family == "aix"
* @run main/othervm AIXTzMappingTest
*/

import java.util.TimeZone;

import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;

public class AIXTzMappingTest {

// POSIX TZ strings that should be mapped via tzmappings
private static final String TZ_CET = "CET-1CEST,M3.5.0,M10.5.0";
private static final String TZ_MEZ = "MEZ-1MESZ,M3.5.0,M10.5.0/3";

private static final String ID_PARIS = "Europe/Paris";
private static final String ID_BERLIN = "Europe/Berlin";

public static void main(String[] args) throws Throwable {
if (args.length == 0) {
runWithTZ(TZ_CET, ID_PARIS);
runWithTZ(TZ_MEZ, ID_BERLIN);
} else if (args.length == 1) {
runTZTest(args[0]);
} else {
throw new RuntimeException(
"Expected 0 or 1 arguments, got " + args.length);
}
}

private static void runWithTZ(String tz, String expectedId)
throws Throwable {
ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(
"AIXTzMappingTest", expectedId);

pb.environment().put("TZ", tz);

OutputAnalyzer output = ProcessTools.executeProcess(pb);
output.shouldHaveExitValue(0);
}

/*
* On AIX, POSIX TZ strings such as:
* CET-1CEST,M3.5.0,M10.5.0
* MEZ-1MESZ,M3.5.0,M10.5.0/3
* are truncated at the comma and mapped through tzmappings to
* IANA timezone IDs.
*
* This test verifies that the expected IANA timezone ID is selected.
*/
private static void runTZTest(String expectedId) {
String tzStr = System.getenv("TZ");

if (tzStr == null) {
throw new RuntimeException(
"Got unexpected timezone information: TZ is null");
}

TimeZone tz = TimeZone.getDefault();
String tzId = tz.getID();

if (!expectedId.equals(tzId)) {
throw new RuntimeException(
"Expected timezone ID " + expectedId
+ " but got " + tzId
+ " for TZ=" + tzStr);
}

System.out.println(
"AIX timezone mapping test passed: "
+ tzId + " for TZ=" + tzStr);
}
}
7 changes: 5 additions & 2 deletions test/jdk/java/util/TimeZone/CustomTzIDCheckDST.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -26,7 +26,10 @@
* @library /test/lib
* @summary This test will ensure that daylight savings rules are followed
* appropriately when setting a custom timezone ID via the TZ env variable.
* @requires os.family != "windows"
* AIX is excluded because it uses a different timezone mapping mechanism
* through the tzmappings file; see AIXTzMappingTest.java for AIX-specific
* coverage.
* @requires os.family != "windows" & os.family != "aix"
* @run main/othervm CustomTzIDCheckDST
*/

Expand Down