001/*
002 * Copyright © 2025 CUI-OpenSource-Software (info@cuioss.de)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package de.cuioss.test.generator.impl;
017
018import de.cuioss.test.generator.Generators;
019import de.cuioss.test.generator.TypedGenerator;
020
021import java.time.ZonedDateTime;
022
023import static de.cuioss.test.generator.Generators.integers;
024
025/**
026 * Generates {@link ZonedDateTime} instances with random dates, times, and time zones.
027 * This generator combines date generation with zone ID generation to create complete
028 * zoned date-time values.
029 *
030 * <p>Features:</p>
031 * <ul>
032 *   <li>Generates valid ZonedDateTime instances</li>
033 *   <li>Uses {@link Generators#dates()} for the date-time component</li>
034 *   <li>Uses {@link Generators#zoneIds()} for the time zone component</li>
035 *   <li>Provides utility methods for common test scenarios</li>
036 *   <li>Thread-safe implementation</li>
037 * </ul>
038 *
039 * <p><em>Example usage:</em></p>
040 * <pre>
041 * // Using the generator directly
042 * var generator = new ZonedDateTimeGenerator();
043 * ZonedDateTime dateTime = generator.next();
044 *
045 * // Using convenience methods
046 * ZonedDateTime any = ZonedDateTimeGenerator.any();
047 * ZonedDateTime future = ZonedDateTimeGenerator.future();
048 * ZonedDateTime past = ZonedDateTimeGenerator.past();
049 * </pre>
050 *
051 * <p>This generator is particularly useful for testing:</p>
052 * <ul>
053 *   <li>Time zone conversions</li>
054 *   <li>Date-time formatting and parsing</li>
055 *   <li>Temporal calculations across time zones</li>
056 * </ul>
057 *
058 * @author Eugen Fischer
059 * @see ZonedDateTime
060 * @see Generators#dates()
061 * @see Generators#zoneIds()
062 */
063public class ZonedDateTimeGenerator implements TypedGenerator<ZonedDateTime> {
064
065    private static final TypedGenerator<Integer> SOME_INT = integers(1, 10);
066
067    @Override
068    public ZonedDateTime next() {
069        return ZonedDateTime.ofInstant(Generators.dates().next().toInstant(), Generators.zoneIds().next());
070    }
071
072    @Override
073    public Class<ZonedDateTime> getType() {
074        return ZonedDateTime.class;
075    }
076
077    /**
078     * @return an arbitrary ZonedDateTime
079     */
080    public static ZonedDateTime any() {
081        return new ZonedDateTimeGenerator().next();
082    }
083
084    /**
085     * @return value of ZonedDateTime for now
086     */
087    public static ZonedDateTime now() {
088        return ZonedDateTime.now();
089    }
090
091    /**
092     * @return value of ZonedDateTime one hour ago
093     */
094    public static ZonedDateTime someMinutesAgo() {
095        return now().minusMinutes(SOME_INT.next());
096    }
097
098    /**
099     * @return value of ZonedDateTime one hour ago
100     */
101    public static ZonedDateTime someHoursAgo() {
102        return now().minusHours(SOME_INT.next());
103    }
104
105    /**
106     * @return value of ZonedDateTime one day ago
107     */
108    public static ZonedDateTime someDaysAgo() {
109        return now().minusDays(SOME_INT.next());
110    }
111
112    /**
113     * @return value of ZonedDateTime one week ago
114     */
115    public static ZonedDateTime someWeeksAgo() {
116        return now().minusWeeks(SOME_INT.next());
117    }
118
119    /**
120     * @return value of ZonedDateTime one month ago
121     */
122    public static ZonedDateTime someMonthsAgo() {
123        return now().minusMonths(SOME_INT.next());
124    }
125
126    /**
127     * @return value of ZonedDateTime one year ago
128     */
129    public static ZonedDateTime someYearsAgo() {
130        return now().minusYears(SOME_INT.next());
131    }
132
133    /**
134     * @return value of ZonedDateTime with date somewhere 10 years ago
135     */
136    public static ZonedDateTime lastTenYearsAgo() {
137        return now().minusYears(10);
138    }
139
140    /**
141     * @return value of ZonedDateTime with date somewhere lastMonth
142     */
143    public static ZonedDateTime lastMonthAgo() {
144        return now().minusMonths(1);
145    }
146}