diff --git a/.gitignore b/.gitignore
index a6f89c2..7fc1d66 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,7 @@
-/target/
\ No newline at end of file
+/target/
+/nbproject/
+/.vscode/
+/.settings/
+.classpath
+.project
+nb-configuration.xml
\ No newline at end of file
diff --git a/nbproject/project.properties b/nbproject/project.properties
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/nbproject/project.properties
diff --git a/pom.xml b/pom.xml
index 39a14c5..4a494b5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0
ua.net.uid
uid.tools
- 1.0.1-SNAPSHOT
+ 1.0.2-SNAPSHOT
jar
diff --git a/pom.xml.releaseBackup b/pom.xml.releaseBackup
new file mode 100644
index 0000000..39a14c5
--- /dev/null
+++ b/pom.xml.releaseBackup
@@ -0,0 +1,116 @@
+
+
+ 4.0.0
+ ua.net.uid
+ uid.tools
+ 1.0.1-SNAPSHOT
+ jar
+
+
+
+ ASL
+ http://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ 5.5.1
+ test
+
+
+
+ com.h2database
+ h2
+ [1.4.193, 1.5.0)
+ test
+
+
+
+
+
+
+ .
+
+ LICENSE
+ NOTICE.txt
+ RELEASE.txt
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.0
+
+ 1.8
+ 1.8
+ true
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.22.2
+
+
+ maven-failsafe-plugin
+ 2.22.2
+
+
+ org.apache.maven.plugins
+ maven-release-plugin
+ 2.5.3
+
+ true
+ @{project.version}
+
+ false
+
+
+
+
+
+
+ UTF-8
+ 1.8
+ 1.8
+ uid-releases
+
+
+
+
+ ua.net.uid-releases
+ https://git.uid.net.ua/maven/releases/
+
+
+ ua.net.uid-snapshots
+ https://git.uid.net.ua/maven/snapshots/
+
+
+
+
+ scm:git:https://git.uid.net.ua/git/uid/uid.tools.git
+ scm:git:https://git.uid.net.ua/git/uid/uid.tools.git
+ https://git.uid.net.ua/git/uid/uid.tools.git
+ HEAD
+
+
+
+
+ uid-releases
+ Release repository
+ https://git.uid.net.ua/maven/releases/
+
+
+ uid-snapshots
+ Snapshots repository
+ https://git.uid.net.ua/maven/snapshots/
+
+
+
\ No newline at end of file
diff --git a/release.properties b/release.properties
new file mode 100644
index 0000000..dd20bf4
--- /dev/null
+++ b/release.properties
@@ -0,0 +1,20 @@
+#release configuration
+#Fri Sep 27 18:54:45 EEST 2019
+scm.commentPrefix=[maven-release-plugin]
+project.scm.ua.net.uid\:uid.tools.tag=HEAD
+pushChanges=true
+project.dev.ua.net.uid\:uid.tools=1.0.2-SNAPSHOT
+project.scm.ua.net.uid\:uid.tools.url=https\://git.uid.net.ua/git/uid/uid.tools.git
+scm.tag=1.0.1
+remoteTagging=true
+projectVersionPolicyId=default
+scm.id=uid-releases
+scm.url=scm\:git\:https\://git.uid.net.ua/git/uid/uid.tools.git
+scm.tagNameFormat=@{project.version}
+preparationGoals=clean verify
+project.scm.ua.net.uid\:uid.tools.developerConnection=scm\:git\:https\://git.uid.net.ua/git/uid/uid.tools.git
+exec.snapshotReleasePluginAllowed=false
+project.scm.ua.net.uid\:uid.tools.connection=scm\:git\:https\://git.uid.net.ua/git/uid/uid.tools.git
+project.scm.ua.net.uid\:uid.tools.id=uid-releases
+completedPhase=end-release
+project.rel.ua.net.uid\:uid.tools=1.0.1
diff --git a/src/main/java/ua/net/uid/utils/helpers/CommonHelper.java b/src/main/java/ua/net/uid/utils/helpers/CommonHelper.java
index 4ca0bd6..efd07d8 100644
--- a/src/main/java/ua/net/uid/utils/helpers/CommonHelper.java
+++ b/src/main/java/ua/net/uid/utils/helpers/CommonHelper.java
@@ -53,11 +53,14 @@
public static boolean isEmpty(T[] array) {
return array == null || array.length == 0;
}
-
+
+ @SafeVarargs
public static Set setOf(T ... items) {
- Set result = new HashSet<>();
- if (!isEmpty(items))
+ if (!isEmpty(items)) {
+ Set result = new HashSet<>(items.length);
Collections.addAll(result, items);
- return result;
+ return result;
+ }
+ return new HashSet<>();
}
}
diff --git a/src/main/java/ua/net/uid/utils/helpers/StringHelper.java b/src/main/java/ua/net/uid/utils/helpers/StringHelper.java
index c767bee..2b9e512 100644
--- a/src/main/java/ua/net/uid/utils/helpers/StringHelper.java
+++ b/src/main/java/ua/net/uid/utils/helpers/StringHelper.java
@@ -16,6 +16,7 @@
package ua.net.uid.utils.helpers;
import java.io.IOException;
+import java.util.Iterator;
public class StringHelper {
private static final char[] HEX_CHARS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
@@ -160,7 +161,6 @@
return string == null ? null : string.trim();
}
- @SuppressWarnings("SpellCheckingInspection")
public static String ltrim(String string) {
if (string == null) return null;
int i = 0, length = string.length();
@@ -169,7 +169,6 @@
return i == 0 ? string : (i < length ? string.substring(i) : "");
}
- @SuppressWarnings("SpellCheckingInspection")
public static String rtrim(String string) {
if (string == null) return null;
int i = string.length();
@@ -184,6 +183,42 @@
return offset;
}
+ public static void join(Appendable builder, CharSequence div, Iterator> iterator) throws IOException {
+ join(builder, div, iterator, true, true);
+ }
+
+ public static void join(Appendable builder, CharSequence div, Iterator> iterator, boolean skipEmpty) throws IOException {
+ join(builder, div, iterator, skipEmpty, skipEmpty);
+ }
+
+ public static void join(Appendable builder, CharSequence div, Iterator> iterator, boolean skipEmpty, boolean skipNull) throws IOException {
+ boolean first = true;
+ while (iterator.hasNext()) {
+ Object item = iterator.next();
+ if (!skipNull || item != null) {
+ String str = String.valueOf(item);
+ if (!(skipEmpty && CommonHelper.isEmpty(str))) {
+ if (first) first = false; else builder.append(div);
+ builder.append(item.toString());
+ }
+ }
+ }
+ }
+
+ public static CharSequence join(CharSequence div, Iterator> iterator) {
+ return join(div, iterator, true, true);
+ }
+
+ public static CharSequence join(CharSequence div, Iterator> iterator, boolean skipEmpty) {
+ return join(div, iterator, skipEmpty, skipEmpty);
+ }
+
+ public static CharSequence join(CharSequence div, Iterator> iterator, boolean skipEmpty, boolean skipNull) {
+ StringBuilder builder = new StringBuilder();
+ try { join(builder, div, iterator, skipEmpty, skipNull); } catch (IOException ignore) {}
+ return builder;
+ }
+
public static boolean isAscii(int chr) {
return ((chr & 0xFFFFFF80) == 0);
}
diff --git a/src/main/java/ua/net/uid/utils/io/ExpiringCache.java b/src/main/java/ua/net/uid/utils/io/ExpiringCache.java
index 6ad3a73..5030b7e 100644
--- a/src/main/java/ua/net/uid/utils/io/ExpiringCache.java
+++ b/src/main/java/ua/net/uid/utils/io/ExpiringCache.java
@@ -17,351 +17,125 @@
import java.util.Date;
import java.util.Objects;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.DelayQueue;
+import java.util.concurrent.Delayed;
+import java.util.concurrent.TimeUnit;
import java.util.function.Function;
public class ExpiringCache {
////////////////////////////////////////////////////////////////////////////
- public static final int MAX_TABLE_SIZE = Integer.MAX_VALUE >>> 3;
- public static final int INIT_SIZE = 64;
- public static final float LOAD_FACTOR = 7F/3F;
+ private final Item EMPTY = new Item<>(null, null, 0);
+ private final ConcurrentHashMap> cache;
+ private final DelayQueue- > queue = new DelayQueue<>();
////////////////////////////////////////////////////////////////////////////
- private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
- private final AtomicInteger count = new AtomicInteger(0);
- private final AtomicInteger modified = new AtomicInteger(0);
- private final float loadFactor;
- private int nextResize;
- private Chain[] table;
-
-
public ExpiringCache() {
- this(INIT_SIZE, LOAD_FACTOR);
+ cache = new ConcurrentHashMap<>();
}
+
public ExpiringCache(int initSize) {
- this(initSize, LOAD_FACTOR);
+ cache = new ConcurrentHashMap<>(initSize);
}
- public ExpiringCache(float loadFactor) {
- this(INIT_SIZE, loadFactor);
- }
- public ExpiringCache(int initSize, float loadFactor) {
- this.loadFactor = loadFactor;
- this.nextResize = (int)(loadFactor * initSize);
- this.table = create(initSize);
- }
-
- public int getSize() { return count.get(); }
-
- public int getTableSize() { return table.length; }
-
- int getModifiedCount() { return modified.get(); }
+ ////////////////////////////////////////////////////////////////////////////
+ public int getSize() { return cache.size(); }
public V get(K key) {
- return get(key, now());
- }
-
- public V get(K key, long now) {
- return chain(key.hashCode()).get(key, now);
+ return cache.getOrDefault(key, EMPTY).value;
}
public V get(K key, Function callback, long ttl) {
- return get(key, callback, ttl, now());
+ return cache.computeIfAbsent(key, (k) -> {
+ Item item = new Item<>(key, callback.apply(key), now() + ttl);
+ queue.put(item);
+ return item;
+ }).value;
}
public V get(K key, Function callback, Date expiry) {
- return get(key, callback, expiry, now());
+ return cache.computeIfAbsent(key, (k) -> {
+ Item item = new Item<>(key, callback.apply(key), expiry.getTime());
+ queue.put(item);
+ return item;
+ }).value;
}
- public V get(K key, Function callback, long ttl, long now) {
- return chain(key.hashCode()).get(key, callback, now + ttl, now);
- }
-
- public V get(K key, Function callback, Date expiry, long now) {
- return chain(key.hashCode()).get(key, callback, expiry.getTime(), now);
- }
-
public void set(K key, V value, long ttl) {
- set(key, value, ttl, now());
+ Item item = new Item<>(key, value, now() + ttl);
+ queue.put(item);
+ cache.put(item.key, item);
}
-
+
public void set(K key, V value, Date expiry) {
- set(key, value, expiry, now());
+ Item item = new Item<>(key, value, expiry.getTime());
+ queue.put(item);
+ cache.put(item.key, item);
}
- public void set(K key, V value, long ttl, long now) {
- chain(key.hashCode()).set(key, value, ttl + now, now);
- }
-
- public void set(K key, V value, Date expiry, long now) {
- chain(key.hashCode()).set(key, value, expiry.getTime(), now);
- }
-
public void remove(K key) {
- remove(key, now());
- }
-
- public void remove(K key, long now) {
- chain(key.hashCode()).remove(key, now);
- }
-
- public V extract(K key) {
- return extract(key, now());
- }
-
- public V extract(K key, long now) {
- return chain(key.hashCode()).extract(key, now);
- }
-
- public void gc() {
- lock.readLock().lock();
- try {
- long now = now();
- for(Chain chain: table)
- chain.gc(now);
- modified.set(0);
- } finally {
- lock.readLock().unlock();
- }
- }
- /*
- //TODO public void pack()
- public void pack() {
- lock.writeLock().lock();
- try {
- throw new UnsupportedOperationException("TODO: Not supported yet.");
- } finally {
- lock.writeLock().unlock();
- }
- }
- */
- public void empty() {
- lock.readLock().lock();
- try {
- for(Chain chain: table)
- chain.next = null;
- modified.set(0);
- } finally {
- lock.readLock().unlock();
- }
+ queue.remove(cache.remove(key));
}
- public void clear(int initSize) {
- lock.writeLock().lock();
- try {
- table = create(initSize);
- modified.set(0);
- } finally {
- lock.writeLock().unlock();
+ public void gc() {
+ Item item;
+ while((item = queue.poll()) != null)
+ cache.remove(item.key, item);
+ }
+
+ public void runGC() {
+ while (!Thread.currentThread().isInterrupted()) {
+ try {
+ Item item = queue.take();
+ cache.remove(item.key, item);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
}
}
public void clear() {
- clear(INIT_SIZE);
+ cache.clear();
}
////////////////////////////////////////////////////////////////////////////
private static long now() { return System.currentTimeMillis(); }
-
- private Chain[] create(int size) {
- Chain[] result = (Chain[]) new Chain[size];
- for(int i = 0; i < size; ++i)
- result[i] = new Chain<>(this);
- return result;
- }
-
- private static int index(int hash, int length) {
- return (hash & MAX_TABLE_SIZE) % length;
- }
-
- private Chain chain(int hash) {
- lock.readLock().lock();
- try {
- return table[index(hash, table.length)];
- } finally {
- lock.readLock().unlock();
- }
- }
-
- private void resize(int delta) {
- int newSize = Math.min(MAX_TABLE_SIZE, count.addAndGet(delta));
- if (newSize > nextResize) {
- lock.writeLock().lock();
- try {
- Chain[] result = create(newSize);
- int newCount = 0;
- long now = now();
- for(Chain src : table) {
- Entry old = src.next;
- while (old != null && old.expiry > now) {
- result[index(old.key.hashCode(), newSize)].add(old.key, old.value, old.expiry);
- ++newCount;
- old = old.next;
- }
- src.next = null;
- }
- table = result;
- count.set(newCount);
- modified.set(0);
- nextResize = Math.min(MAX_TABLE_SIZE, (int)(loadFactor * newSize));
- } finally {
- lock.writeLock().unlock();
- }
- } else {
- if (modified.incrementAndGet() > nextResize)
- gc();
- }
- }
+ private static int compare(long lv, long rv) { return lv < rv ? -1 : (lv > rv ? 1 : 0); }
////////////////////////////////////////////////////////////////////////////
- private static abstract class Item {
- Entry next;
- Item(Entry next) { this.next = next; }
- }
- ////////////////////////////////////////////////////////////////////////////
- private static final class Entry extends Item {
+ private static final class Item implements Delayed {
final K key;
final V value;
final long expiry;
- Entry(K key, V value, long expiry, Entry next) {
- super(next);
- this.expiry = expiry;
+
+ public Item(K key, V value, long expiry) {
this.key = key;
this.value = value;
+ this.expiry = expiry;
}
- }
- ////////////////////////////////////////////////////////////////////////////
- private static final class Chain extends Item {
- final ExpiringCache cache;
- int count = 0;
-
- Chain(ExpiringCache cache) {
- super(null);
- this.cache = cache;
+
+ @Override
+ public long getDelay(TimeUnit unit) {
+ return unit.convert(expiry - now(), TimeUnit.MILLISECONDS);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public int compareTo(Delayed other) {
+ return compare(expiry, ((Item)other).expiry);
+ }
+
+ @Override
+ public int hashCode() {
+ return 23 * (23 * (23 * 7 + Objects.hashCode(key)) + Objects.hashCode(value)) + (int) (expiry ^ (expiry >>> 32));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other instanceof Item && equals((Item, ?>) other);
}
- private void count(int value) {
- if (count != value) {
- int old = count;
- count = value;
- cache.resize(value - old);
- }
- }
-
- private boolean checkNext(Item current, long now) {
- if (current.next != null) {
- if (current.next.expiry <= now) {
- current.next = null;
- } else {
- return true;
- }
- }
- return false;
- }
-
- void add(K key, V value, long expiry) {
- Item item = this;
- while (item.next != null && item.next.expiry > expiry) {
- item = item.next;
- }
- item.next = new Entry<>(key, value, expiry, item.next);
- ++count;
- }
-
- synchronized V get(K key, long now) {
- Item item = this;
- int cnt = 0;
- V result = null;
- while (checkNext(item, now)) {
- if (Objects.equals(key, item.next.key))
- result = item.next.value;
- ++cnt;
- item = item.next;
- }
- count(cnt);
- return result;
- }
-
- synchronized V get(K key, Function callback, long expiry, long now) {
- Item item = this, last = this;
- int cnt = 0;
- while (checkNext(item, now)) {
- ++cnt;
- if (Objects.equals(key, item.next.key)) {
- V value = item.next.value;
- while (checkNext(item = item.next, now)) ++cnt;
- count(cnt);
- return value;
- }
- if (item.next.expiry > expiry)
- last = item.next;
- item = item.next;
- }
- V value = callback.apply(key);
- last.next = new Entry<>(key, value, expiry, last.next);
- count(cnt + 1);
- return value;
- }
-
- synchronized void set(K key, V value, long expiry, long now) {
- Item item = this, last = this;
- int cnt = 0;
- while (checkNext(item, now)) {
- if (Objects.equals(key, item.next.key)) {
- item.next = item.next.next;
- while (checkNext(item, now)) {
- ++cnt;
- if (item.next.expiry > expiry)
- last = item.next;
- item = item.next;
- }
- break;
- }
- ++cnt;
- if (item.next.expiry > expiry)
- last = item.next;
- item = item.next;
- }
- last.next = new Entry<>(key, value, expiry, last.next);
- count(cnt + 1);
- }
-
- synchronized void remove(K key, long now) {
- Item item = this;
- int cnt = 0;
- while (checkNext(item, now)) {
- if (Objects.equals(key, item.next.key)) {
- item.next = item.next.next;
- } else {
- ++cnt;
- item = item.next;
- }
- }
- count(cnt);
- }
-
- synchronized V extract(K key, long now) {
- Item item = this;
- int cnt = 0;
- V result = null;
- while (checkNext(item, now)) {
- if (Objects.equals(key, item.next.key)) {
- result = item.next.value;
- item.next = item.next.next;
- } else {
- ++cnt;
- item = item.next;
- }
- }
- count(cnt);
- return result;
- }
-
- synchronized void gc(long now) {
- Item item = this;
- int cnt = 0;
- while (checkNext(item, now)) {
- ++cnt;
- item = item.next;
- }
- count(cnt);
+ public boolean equals(Item, ?> other) {
+ return other != null
+ && Objects.equals(key, other.key)
+ && expiry == other.expiry
+ && Objects.equals(value, other.value);
}
}
////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/ua/net/uid/utils/io/FifoCache.java b/src/main/java/ua/net/uid/utils/io/FifoCache.java
new file mode 100644
index 0000000..3f3f074
--- /dev/null
+++ b/src/main/java/ua/net/uid/utils/io/FifoCache.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 nightfall.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ua.net.uid.utils.io;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.function.Function;
+
+/**
+ *
+ * @author nightfall
+ */
+public class FifoCache {
+ private final ConcurrentHashMap cache = new ConcurrentHashMap<>();
+ private final ConcurrentLinkedDeque fifo = new ConcurrentLinkedDeque<>();
+ private final int limit;
+
+ public FifoCache(int limit) {
+ this.limit = limit;
+ }
+
+ public V get(K key, Function callback) {
+ return cache.computeIfAbsent(key, (k) -> {
+ try {
+ fifo.addLast(k);
+ return callback.apply(k);
+ } finally {
+ if (fifo.size() > limit)
+ cache.remove(fifo.removeFirst());
+ }
+ });
+ }
+}
diff --git a/src/main/java/ua/net/uid/utils/time/DailyEquation.java b/src/main/java/ua/net/uid/utils/time/DailyEquation.java
new file mode 100644
index 0000000..4b31cdb
--- /dev/null
+++ b/src/main/java/ua/net/uid/utils/time/DailyEquation.java
@@ -0,0 +1,105 @@
+package ua.net.uid.utils.time;
+
+import java.util.Calendar;
+
+/**
+ *
+ *
+ * https://web.archive.org/web/20161202180207/http://williams.best.vwh.net/sunrise_sunset_algorithm.htm
+ * http://edwilliams.org/sunrise_sunset_algorithm.htm
+ * https://edwilliams.org/sunrise_sunset_example.htm
+ *
+ * https://github.com/KlausBrunner/solarpositioning
+ * https://github.com/mikereedell/sunrisesunsetlib-java
+ * https://github.com/shred/commons-suncalc
+ * https://gist.github.com/Tafkas/4742250
+ *
+ * https://github.com/caarmen/SunriseSunset
+ * http://users.electromagnetic.net/bu/astro/sunrise-set.php
+ *
+ *
+ * https://www.aa.quae.nl/en/reken/zonpositie.html
+ *
+ * TODO: переделать под java.time
+ *
+ * @author nightfall
+ */
+public class DailyEquation {
+ public static DailyEvents getSunEvents(double latitude, double longitude, Calendar calendar, Zenith zenith) {
+ return getSunEvents(latitude, longitude, calendar, zenith.getDegrees());
+ }
+
+ public static DailyEvents getSunEvents(double latitude, double longitude, Calendar calendar, double zenith) {
+ longitude /= 15;
+ int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
+
+ double sunrizeTime = calculateEvent(latitude, longitude, zenith, dayOfYear, true);
+ double sunsetTime = calculateEvent(latitude, longitude, zenith, dayOfYear, false);
+
+ if (sunrizeTime == Double.NEGATIVE_INFINITY || sunsetTime == Double.NEGATIVE_INFINITY) { // the sun never rises on this location (on the specified date)
+ return new DailyEvents(null, null, DailyEventType.POLAR_NIGHT);
+ } else if (sunrizeTime == Double.POSITIVE_INFINITY || sunsetTime == Double.POSITIVE_INFINITY) { // the sun never sets on this location (on the specified date)
+ return new DailyEvents(null, null, DailyEventType.POLAR_DAY);
+ } else {
+ return new DailyEvents(convertDate(calendar, sunrizeTime), convertDate(calendar, sunsetTime), DailyEventType.NORMAL_DAY);
+ }
+ }
+
+ protected static double calculateEvent(double latitude, double baseLongitudeHour, double zenith, int dayOfYear, boolean rising) {
+ //t = ((rising ? 6 : 18) - lngHour) / 24 + dayOfYear;
+ double longitudeHour = ((rising ? 6 : 18) - baseLongitudeHour) / 24 + dayOfYear;
+ // M = 0.9856 * t - 3.289;
+ double meanAnomaly = 0.9856 * longitudeHour - 3.289;
+ double meanAnomalyRadians = Math.toRadians(meanAnomaly);
+ // L = M + (1.916 * sin(M)) + (0.020 * sin(2 * M)) + 282.634
+ double sunTrueLong = meanAnomaly + (1.916 * Math.sin(meanAnomalyRadians)) + (0.020 * Math.sin(2 * meanAnomalyRadians)) + 282.634; // L
+ if (sunTrueLong > 360) sunTrueLong -= 360;
+
+ // sinDec = 0.39782 * sin(L);
+ double sinSunDeclination = 0.39782 * Math.sin(Math.toRadians(sunTrueLong));
+ // cosDec = cos(asin(sinDec));
+ double cosineSunDeclination = Math.cos(Math.asin(sinSunDeclination));
+ // cosH = (cos(zenith) - (sinDec * sin(latitude))) / (cosDec * cos(latitude));
+ double latitudeRadians = Math.toRadians(latitude);
+ double cosineSunLocalHour = (Math.cos(Math.toRadians(zenith)) - sinSunDeclination * Math.sin(latitudeRadians))
+ / (cosineSunDeclination * Math.cos(latitudeRadians));
+
+ if (cosineSunLocalHour > 1) return Double.NEGATIVE_INFINITY; // the sun never rises on this location (on the specified date)
+ if (cosineSunLocalHour < -1) return Double.POSITIVE_INFINITY; // the sun never sets on this location (on the specified date)
+
+ // H = (rising ? 360 - acos(cosH) : acos(cosH)) / 15;
+ double sunLocalHour = Math.toDegrees(Math.acos(cosineSunLocalHour));
+ sunLocalHour = (rising ? 360 - sunLocalHour : sunLocalHour) / 15;
+
+ // RA = atan(0.91764 * tan(L)); // RA
+ //double rightAscension = Math.atan(Math.toRadians(0.91764 * Math.toDegrees( Math.tan(Math.toRadians(sunTrueLong)) )));
+ double rightAscension = Math.toDegrees(Math.atan(Math.toRadians(0.91764 * Math.toDegrees( Math.tan(Math.toRadians(sunTrueLong)) ))));
+
+ //--- //RA potentially needs to be adjusted into the range [0,360) by adding/subtracting 360
+ //--- if (rightAscension < 0) { rightAscension += 360; } else if (rightAscension > 360) { rightAscension -= 360; }
+ // RA = (RA + (floor(L/90) - floor(RA/90)) * 90) / 15;
+ rightAscension = (rightAscension + (Math.floor(sunTrueLong / 90) - Math.floor(rightAscension / 90)) * 90) / 15;
+
+ // T = H + RA - (0.06571 * t) - 6.622
+ double localMeanTime = sunLocalHour + rightAscension - (longitudeHour * 0.06571) - 6.622; // T
+
+ // UT = T - lngHour
+ return localMeanTime - baseLongitudeHour;
+ }
+
+ protected static long convertDate(Calendar calendar, double utcTime) {
+ // localT = UT + localOffset
+ int time = (int)(utcTime * 3600000) + calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
+ // UT potentially needs to be adjusted into the range [0,24) by adding/subtracting 24
+ //if (utcTime >= 24.) utcTime -= 24; else if (utcTime < 0) utcTime += 24;
+ if (time >= DAYMSEC) time -= DAYMSEC; else if (time < 0) time += DAYMSEC;
+ calendar.set(Calendar.HOUR_OF_DAY, 0);
+ calendar.set(Calendar.MINUTE, 0);
+ calendar.set(Calendar.SECOND, 0);
+ calendar.set(Calendar.MILLISECOND, 0);
+ calendar.add(Calendar.MILLISECOND, time);
+ return calendar.getTimeInMillis();
+ }
+
+ private static final int DAYMSEC = 24 * 60 * 60 * 1000;
+}
diff --git a/src/main/java/ua/net/uid/utils/time/DailyEventType.java b/src/main/java/ua/net/uid/utils/time/DailyEventType.java
new file mode 100644
index 0000000..26bab43
--- /dev/null
+++ b/src/main/java/ua/net/uid/utils/time/DailyEventType.java
@@ -0,0 +1,17 @@
+package ua.net.uid.utils.time;
+
+public enum DailyEventType {
+ NORMAL_DAY("normal"),
+ POLAR_NIGHT("night"),
+ POLAR_DAY("day");
+
+ private final String title;
+
+ DailyEventType(String title) {
+ this.title = title;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+}
diff --git a/src/main/java/ua/net/uid/utils/time/DailyEvents.java b/src/main/java/ua/net/uid/utils/time/DailyEvents.java
new file mode 100644
index 0000000..a88e146
--- /dev/null
+++ b/src/main/java/ua/net/uid/utils/time/DailyEvents.java
@@ -0,0 +1,25 @@
+package ua.net.uid.utils.time;
+
+public class DailyEvents {
+ private final Long sunrise;
+ private final Long sunset;
+ private final DailyEventType type;
+
+ DailyEvents(Long sunrise, Long sunset, DailyEventType type) {
+ this.sunrise = sunrise;
+ this.sunset = sunset;
+ this.type = type;
+ }
+
+ public Long getSunrise() {
+ return sunrise;
+ }
+
+ public Long getSunset() {
+ return sunset;
+ }
+
+ public DailyEventType getType() {
+ return type;
+ }
+}
diff --git a/src/main/java/ua/net/uid/utils/time/Zenith.java b/src/main/java/ua/net/uid/utils/time/Zenith.java
new file mode 100644
index 0000000..5317e8d
--- /dev/null
+++ b/src/main/java/ua/net/uid/utils/time/Zenith.java
@@ -0,0 +1,18 @@
+package ua.net.uid.utils.time;
+
+public enum Zenith {
+ ASTRONOMICAL(108.), // Astronomical sunrise/set is when the sun is 18 degrees below the horizon.
+ NAUTICAL(102.), // Nautical sunrise/set is when the sun is 12 degrees below the horizon.
+ CIVIL(96.), // Civil sunrise/set (dawn/dusk) is when the sun is 6 degrees below the horizon.
+ OFFICIAL(90.8333); // Official sunrise/set is when the sun is 50' below the horizon.
+
+ private final double degrees;
+
+ Zenith(double degrees) {
+ this.degrees = degrees;
+ }
+
+ public double getDegrees() {
+ return degrees;
+ }
+}
diff --git a/src/main/java/ua/net/uid/utils/tools/DailyEquation.java b/src/main/java/ua/net/uid/utils/tools/DailyEquation.java
deleted file mode 100644
index 90eefeb..0000000
--- a/src/main/java/ua/net/uid/utils/tools/DailyEquation.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright 2019 nightfall.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package ua.net.uid.utils.tools;
-
-import java.util.Calendar;
-
-/**
- *
- *
- * https://web.archive.org/web/20161202180207/http://williams.best.vwh.net/sunrise_sunset_algorithm.htm
- * http://edwilliams.org/sunrise_sunset_algorithm.htm
- * https://edwilliams.org/sunrise_sunset_example.htm
- *
- * https://github.com/KlausBrunner/solarpositioning
- * https://github.com/mikereedell/sunrisesunsetlib-java
- * https://github.com/shred/commons-suncalc
- * https://gist.github.com/Tafkas/4742250
- *
- * https://github.com/caarmen/SunriseSunset
- * http://users.electromagnetic.net/bu/astro/sunrise-set.php
- *
- *
- * https://www.aa.quae.nl/en/reken/zonpositie.html
- *
- * @author nightfall
- */
-public class DailyEquation {
- ////////////////////////////////////////////////////////////////////////////
- public enum Zenith {
- ASTRONOMICAL(108.), // Astronomical sunrise/set is when the sun is 18 degrees below the horizon.
- NAUTICAL(102.), // Nautical sunrise/set is when the sun is 12 degrees below the horizon.
- CIVIL(96.), // Civil sunrise/set (dawn/dusk) is when the sun is 6 degrees below the horizon.
- OFFICIAL(90.8333); // Official sunrise/set is when the sun is 50' below the horizon.
-
- private final double degrees;
- Zenith(double degrees) { this.degrees = degrees; }
- public double getDegrees() { return degrees; }
- }
- ////////////////////////////////////////////////////////////////////////////
- public enum Type {
- NORMAL_DAY("normal"),
- POLAR_NIGHT("night"),
- POLAR_DAY("day");
- private final String title;
- Type(String title) { this.title = title; }
- public String getTitle() { return title; }
- }
- ////////////////////////////////////////////////////////////////////////////
- public static class Events {
- private final Long sunrise;
- private final Long sunset;
- private final Type type;
- Events(Long sunrise, Long sunset, Type type) {
- this.sunrise = sunrise;
- this.sunset = sunset;
- this.type = type;
- }
- public Long getSunrise() { return sunrise; }
- public Long getSunset() { return sunset; }
- public Type getType() { return type; }
- }
- ////////////////////////////////////////////////////////////////////////////
- public static Events getSunEvents(double latitude, double longitude, Calendar calendar, Zenith zenith) {
- return getSunEvents(latitude, longitude, calendar, zenith.getDegrees());
- }
- public static Events getSunEvents(double latitude, double longitude, Calendar calendar, double zenith) {
- longitude /= 15;
- int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
-
- double sunrizeTime = calculateEvent(latitude, longitude, zenith, dayOfYear, true);
- double sunsetTime = calculateEvent(latitude, longitude, zenith, dayOfYear, false);
-
- if (sunrizeTime == Double.NEGATIVE_INFINITY || sunsetTime == Double.NEGATIVE_INFINITY) { // the sun never rises on this location (on the specified date)
- return new Events(null, null, Type.POLAR_NIGHT);
- } else if (sunrizeTime == Double.POSITIVE_INFINITY || sunsetTime == Double.POSITIVE_INFINITY) { // the sun never sets on this location (on the specified date)
- return new Events(null, null, Type.POLAR_DAY);
- } else {
- return new Events(convertDate(calendar, sunrizeTime), convertDate(calendar, sunsetTime), Type.NORMAL_DAY);
- }
- }
-
- protected static double calculateEvent(double latitude, double baseLongitudeHour, double zenith, int dayOfYear, boolean rising) {
- //t = ((rising ? 6 : 18) - lngHour) / 24 + dayOfYear;
- double longitudeHour = ((rising ? 6 : 18) - baseLongitudeHour) / 24 + dayOfYear;
- // M = 0.9856 * t - 3.289;
- double meanAnomaly = 0.9856 * longitudeHour - 3.289;
- double meanAnomalyRadians = Math.toRadians(meanAnomaly);
- // L = M + (1.916 * sin(M)) + (0.020 * sin(2 * M)) + 282.634
- double sunTrueLong = meanAnomaly + (1.916 * Math.sin(meanAnomalyRadians)) + (0.020 * Math.sin(2 * meanAnomalyRadians)) + 282.634; // L
- if (sunTrueLong > 360) sunTrueLong -= 360;
-
- // sinDec = 0.39782 * sin(L);
- double sinSunDeclination = 0.39782 * Math.sin(Math.toRadians(sunTrueLong));
- // cosDec = cos(asin(sinDec));
- double cosineSunDeclination = Math.cos(Math.asin(sinSunDeclination));
- // cosH = (cos(zenith) - (sinDec * sin(latitude))) / (cosDec * cos(latitude));
- double latitudeRadians = Math.toRadians(latitude);
- double cosineSunLocalHour = (Math.cos(Math.toRadians(zenith)) - sinSunDeclination * Math.sin(latitudeRadians))
- / (cosineSunDeclination * Math.cos(latitudeRadians));
-
- if (cosineSunLocalHour > 1) return Double.NEGATIVE_INFINITY; // the sun never rises on this location (on the specified date)
- if (cosineSunLocalHour < -1) return Double.POSITIVE_INFINITY; // the sun never sets on this location (on the specified date)
-
- // H = (rising ? 360 - acos(cosH) : acos(cosH)) / 15;
- double sunLocalHour = Math.toDegrees(Math.acos(cosineSunLocalHour));
- sunLocalHour = (rising ? 360 - sunLocalHour : sunLocalHour) / 15;
-
- // RA = atan(0.91764 * tan(L)); // RA
- //double rightAscension = Math.atan(Math.toRadians(0.91764 * Math.toDegrees( Math.tan(Math.toRadians(sunTrueLong)) )));
- double rightAscension = Math.toDegrees(Math.atan(Math.toRadians(0.91764 * Math.toDegrees( Math.tan(Math.toRadians(sunTrueLong)) ))));
-
- //--- //RA potentially needs to be adjusted into the range [0,360) by adding/subtracting 360
- //--- if (rightAscension < 0) { rightAscension += 360; } else if (rightAscension > 360) { rightAscension -= 360; }
- // RA = (RA + (floor(L/90) - floor(RA/90)) * 90) / 15;
- rightAscension = (rightAscension + (Math.floor(sunTrueLong / 90) - Math.floor(rightAscension / 90)) * 90) / 15;
-
- // T = H + RA - (0.06571 * t) - 6.622
- double localMeanTime = sunLocalHour + rightAscension - (longitudeHour * 0.06571) - 6.622; // T
-
- // UT = T - lngHour
- return localMeanTime - baseLongitudeHour;
- }
-
- private static final int DAYMSEC = 24 * 60 * 60 * 1000;
- protected static long convertDate(Calendar calendar, double utcTime) {
- // localT = UT + localOffset
- int time = (int)(utcTime * 3600000) + calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
- // UT potentially needs to be adjusted into the range [0,24) by adding/subtracting 24
- //if (utcTime >= 24.) utcTime -= 24; else if (utcTime < 0) utcTime += 24;
- if (time >= DAYMSEC) time -= DAYMSEC; else if (time < 0) time += DAYMSEC;
- calendar.set(Calendar.HOUR_OF_DAY, 0);
- calendar.set(Calendar.MINUTE, 0);
- calendar.set(Calendar.SECOND, 0);
- calendar.set(Calendar.MILLISECOND, 0);
- calendar.add(Calendar.MILLISECOND, time);
- return calendar.getTimeInMillis();
- }
-}
diff --git a/src/test/java/ua/net/uid/utils/concurrent/ReadyFutureTest.java b/src/test/java/ua/net/uid/utils/concurrent/ReadyFutureTest.java
index c1e15cc..67975cf 100644
--- a/src/test/java/ua/net/uid/utils/concurrent/ReadyFutureTest.java
+++ b/src/test/java/ua/net/uid/utils/concurrent/ReadyFutureTest.java
@@ -10,32 +10,32 @@
@Test
void testCancel() {
- ReadyFuture instance = new ReadyFuture(null);
+ ReadyFuture> instance = new ReadyFuture<>(null);
assertFalse(instance.cancel(true));
assertFalse(instance.cancel(false));
}
@Test
void testIsCancelled() {
- ReadyFuture instance = new ReadyFuture(null);
+ ReadyFuture> instance = new ReadyFuture<>(null);
assertFalse(instance.isCancelled());
}
@Test
void testIsDone() {
- ReadyFuture instance = new ReadyFuture(null);
+ ReadyFuture> instance = new ReadyFuture<>(null);
assertTrue(instance.isDone());
}
@Test
void testGet() {
- ReadyFuture instance = new ReadyFuture(3);
+ ReadyFuture> instance = new ReadyFuture<>(3);
assertEquals(3, instance.get());
}
@Test
void testGet_long_TimeUnit() {
- ReadyFuture instance = new ReadyFuture(4.4);
+ ReadyFuture> instance = new ReadyFuture<>(4.4);
assertEquals(4.4, instance.get(1, TimeUnit.NANOSECONDS));
}
}
diff --git a/src/test/java/ua/net/uid/utils/helpers/CommonHelperTest.java b/src/test/java/ua/net/uid/utils/helpers/CommonHelperTest.java
index a2e8b33..44db5fd 100644
--- a/src/test/java/ua/net/uid/utils/helpers/CommonHelperTest.java
+++ b/src/test/java/ua/net/uid/utils/helpers/CommonHelperTest.java
@@ -45,9 +45,9 @@
@Test
void testIsEmptyCollection() {
- Collection src = null;
+ Collection