Skip to content

Commit e7da401

Browse files
committed
Initial implementation
+ Add unit tests with AssertJ + Add JavaDoc with examples + Add README.md
1 parent f6b95bd commit e7da401

15 files changed

+1708
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
target/
2+
.idea/
3+
*.iml
4+

README.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Java-Timestream
2+
A set of builders that create streams of java.time objects.
3+
4+
These are fully functional streams, so you can use them like any other stream, once created.
5+
6+
Once `Stream.takeWhile()` support is added in Java 9, this library will not be very useful. The lack
7+
of a convenient `takeWhile(Predicate<T> predicate)` method in Java 8 is what lead to the creation
8+
of this library.
9+
10+
To get Java-Timestream, clone this repository. I am working to get this in Maven Central ASAP.
11+
12+
git clone git://github.com/tginsberg/java-timestream.git
13+
14+
This library can create streams of the following java.time classes:
15+
16+
+ `LocalDate` via `LocalDateStream`
17+
+ `LocalDateTime` via `LocalDateTimeStream`
18+
+ `YearMonth` via `YearMonthStream`
19+
+ `ZonedDateTime` via `ZoneDateTimeStream`
20+
21+
And has support for...
22+
23+
+ Inclusive end point (`to`)
24+
+ Exclusive end point (`until`)
25+
+ Configurable period between stream elements (`every`)
26+
+ Streams can move forward or backward through time
27+
28+
## Usage
29+
30+
Every builder needs a non-null point in time to begin the stream. Therefore, each
31+
builder can be created using one of two methods:
32+
33+
+ `.fromNow()` - Assumes 'now'
34+
+ `.from(T from)` - Type-specific starting point, provided by caller
35+
36+
To set the point in time where the stream ends (optional!), you can call one of two methods:
37+
38+
+ `.to(T to)` - Type-specific end point. Can be null to indicate forever
39+
+ `.to(amount, units)` - Where `amount` is a positive integer (for forward through time) or a negative integer (for backward through time), and `unit` is a valid `ChronoUnit`
40+
41+
## Examples
42+
43+
Create a stream of `LocalDateTime` objects, between now and hour from now, every two minutes:
44+
45+
```java
46+
final Stream<LocalDateTime> stream = LocalDateTimeStream
47+
.fromNow()
48+
.to(1, ChronoUnit.HOURS)
49+
.every(2, ChronoUnit.MINUTES)
50+
.stream();
51+
```
52+
53+
Or (equivalent):
54+
55+
```java
56+
final Stream<LocalDateTime> stream = LocalDateTimeStream
57+
.from(LocalDateTime.now())
58+
.to(LocalDateTime.now().plusHours(1))
59+
.every(2, ChronoUnit.MINUTES)
60+
.stream();
61+
```
62+
63+
Create a stream of `YearMonth` objects from today, to a year ago (backward through time), stopping before the end (exclusive),
64+
every month:
65+
66+
```java
67+
final Stream<YearMonth> stream = YearMonthStream
68+
.fromNow()
69+
.until(-12, ChronoUnit.MONTHS)
70+
.every(1, ChronoUnit.MONTHS) // This is the default
71+
.stream();
72+
```
73+
74+
## Contributing and Issues
75+
76+
Please feel free to file issues for change requests or bugs. If you would like to contribute new functionality, please contact me first!

pom.xml

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<!--
2+
~ MIT License
3+
~
4+
~ Copyright (c) 2016 Todd Ginsberg
5+
~
6+
~ Permission is hereby granted, free of charge, to any person obtaining a copy
7+
~ of this software and associated documentation files (the "Software"), to deal
8+
~ in the Software without restriction, including without limitation the rights
9+
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
~ copies of the Software, and to permit persons to whom the Software is
11+
~ furnished to do so, subject to the following conditions:
12+
~
13+
~ The above copyright notice and this permission notice shall be included in all
14+
~ copies or substantial portions of the Software.
15+
~
16+
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
~ SOFTWARE.
23+
-->
24+
25+
<project xmlns="http://maven.apache.org/POM/4.0.0"
26+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
27+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
28+
29+
<modelVersion>4.0.0</modelVersion>
30+
31+
<groupId>com.ginsberg</groupId>
32+
<artifactId>java-timestream</artifactId>
33+
<description>A set of builders that create streams of java.time objects</description>
34+
<version>1.0-SNAPSHOT</version>
35+
<packaging>jar</packaging>
36+
37+
<licenses>
38+
<license>
39+
<name>MIT License</name>
40+
<url>http://www.opensource.org/licenses/mit-license.php</url>
41+
<distribution>repo</distribution>
42+
</license>
43+
</licenses>
44+
45+
<properties>
46+
<java.version>1.8</java.version>
47+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
48+
</properties>
49+
50+
<build>
51+
<plugins>
52+
<plugin>
53+
<groupId>org.apache.maven.plugins</groupId>
54+
<artifactId>maven-compiler-plugin</artifactId>
55+
<version>3.5.1</version>
56+
<configuration>
57+
<source>${java.version}</source>
58+
<target>${java.version}</target>
59+
</configuration>
60+
</plugin>
61+
62+
<plugin>
63+
<groupId>org.apache.maven.plugins</groupId>
64+
<artifactId>maven-release-plugin</artifactId>
65+
<version>2.5.3</version>
66+
<configuration>
67+
<autoVersionSubmodules>true</autoVersionSubmodules>
68+
<useReleaseProfile>false</useReleaseProfile>
69+
<releaseProfiles>release</releaseProfiles>
70+
<goals>deploy</goals>
71+
</configuration>
72+
</plugin>
73+
</plugins>
74+
</build>
75+
76+
<dependencies>
77+
<!-- Test dependencies -->
78+
<dependency>
79+
<groupId>org.assertj</groupId>
80+
<artifactId>assertj-core</artifactId>
81+
<version>3.4.1</version>
82+
<scope>test</scope>
83+
</dependency>
84+
<dependency>
85+
<groupId>junit</groupId>
86+
<artifactId>junit</artifactId>
87+
<version>4.12</version>
88+
<scope>test</scope>
89+
</dependency>
90+
</dependencies>
91+
92+
<reporting>
93+
<plugins>
94+
<plugin>
95+
<groupId>org.apache.maven.plugins</groupId>
96+
<artifactId>maven-javadoc-plugin</artifactId>
97+
<version>2.10.4</version>
98+
</plugin>
99+
</plugins>
100+
</reporting>
101+
102+
</project>
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* MIT License
3+
*
4+
* Copyright (c) 2016 Todd Ginsberg
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
package com.ginsberg.timestream;
26+
27+
import java.util.Objects;
28+
import java.util.function.Predicate;
29+
import java.util.function.UnaryOperator;
30+
import java.util.stream.Stream;
31+
import java.util.stream.StreamSupport;
32+
33+
import static java.util.stream.Stream.iterate;
34+
35+
/**
36+
* Provides generic support for open and closed-ended ranges of objects
37+
* that can be compared.
38+
*
39+
* @param <T> A type that implements `Comparable`.
40+
* @author Todd Ginsberg (todd@ginsberg.com)
41+
*/
42+
abstract class AbstractComparableStream<T extends Comparable<? super T>> {
43+
private final T from;
44+
private T to;
45+
private boolean closedRange = false;
46+
47+
AbstractComparableStream(final T from) {
48+
Objects.requireNonNull(from);
49+
this.from = from;
50+
}
51+
52+
void setTo(final T to) {
53+
this.to = to;
54+
this.closedRange = false;
55+
}
56+
57+
void setUntil(final T until) {
58+
this.to = until;
59+
this.closedRange = true;
60+
}
61+
62+
boolean isForward() {
63+
return to == null || from.compareTo(to) <= 0;
64+
}
65+
66+
T getFrom() {
67+
return from;
68+
}
69+
70+
/**
71+
* Provide an operator that returns the next value in the series.
72+
* @return A non-null UnaryOperator
73+
*/
74+
abstract UnaryOperator<T> next();
75+
76+
/**
77+
* Produce a stream between the dates given, skipping
78+
* by the amount specified.
79+
*
80+
* @return A non-null stream of time/date.
81+
*/
82+
public Stream<T> stream() {
83+
return StreamSupport.stream(
84+
TakeWhile.of(
85+
iterate(from, next()).spliterator(),
86+
canTake()),
87+
false);
88+
89+
}
90+
91+
/**
92+
* Method that generates a predicate that is used by the Spliterator to
93+
* implement a limitation on the stream. We can take the next value in
94+
* the stream if one of the following are true:
95+
*
96+
* 1) There is no bound to the stream (to is null).
97+
* 2) We are before the end when we are moving forward through time.
98+
* 3) We are after the end when we are moving backward through time.
99+
* 4) The current time equals the end and we are not a closed range.
100+
*
101+
* @return A Predicate
102+
*/
103+
private Predicate<T> canTake() {
104+
return x -> {
105+
if (to == null) {
106+
return true;
107+
} else {
108+
final int compare = x.compareTo(to);
109+
if (compare < 0) {
110+
return isForward();
111+
} else if (compare > 0) {
112+
return !isForward();
113+
} else {
114+
return !closedRange;
115+
}
116+
}
117+
};
118+
}
119+
}

0 commit comments

Comments
 (0)