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 src = null; assertTrue(CommonHelper.isEmpty(src)); - src = new ArrayList(); + src = new ArrayList<>(); assertTrue(CommonHelper.isEmpty(src)); src.add("1"); assertFalse(CommonHelper.isEmpty(src)); @@ -55,9 +55,9 @@ @Test void testIsEmptyMap() { - Map src = null; + Map src = null; assertTrue(CommonHelper.isEmpty(src)); - src = new HashMap(); + src = new HashMap<>(); assertTrue(CommonHelper.isEmpty(src)); src.put(1, "1"); assertFalse(CommonHelper.isEmpty(src)); diff --git a/src/test/java/ua/net/uid/utils/io/ExpiringCacheTest.java b/src/test/java/ua/net/uid/utils/io/ExpiringCacheTest.java index afb3214..c76a221 100644 --- a/src/test/java/ua/net/uid/utils/io/ExpiringCacheTest.java +++ b/src/test/java/ua/net/uid/utils/io/ExpiringCacheTest.java @@ -9,70 +9,7 @@ @Test public void testSavingOfItems() throws Exception { - ExpiringCache instance = new ExpiringCache<>(2, 4f/3f); - - assertEquals(Integer.valueOf(1), instance.get(1, (key) -> key * key, 1500)); - assertEquals(Integer.valueOf(4), instance.get(2, (key) -> key * key, 2000)); - assertEquals(2, instance.getSize()); - assertEquals(2, instance.getTableSize()); - assertEquals(2, instance.getModifiedCount()); - - assertEquals(Integer.valueOf(4), instance.get(2, (key) -> key, 2000)); - assertEquals(2, instance.getSize()); - assertEquals(2, instance.getTableSize()); - assertEquals(2, instance.getModifiedCount()); - - assertEquals(Integer.valueOf(9), instance.get(3, (key) -> key * key, 2000)); - assertEquals(3, instance.getSize()); - assertEquals(3, instance.getTableSize()); - assertEquals(0, instance.getModifiedCount()); - - assertEquals(Integer.valueOf(16), instance.get(4, (key) -> key * key, 2000)); - assertEquals(4, instance.getSize()); - assertEquals(3, instance.getTableSize()); - assertEquals(1, instance.getModifiedCount()); - - assertEquals(Integer.valueOf(25), instance.get(-5, (key) -> key * key, 1000)); - assertEquals(5, instance.getSize()); - assertEquals(5, instance.getTableSize()); - assertEquals(0, instance.getModifiedCount()); - - assertEquals(Integer.valueOf(25), instance.get(-5)); - assertEquals(5, instance.getSize()); - assertEquals(5, instance.getTableSize()); - assertEquals(0, instance.getModifiedCount()); - - assertNull(instance.get(-5, System.currentTimeMillis() + 1000)); - assertEquals(4, instance.getSize()); - assertEquals(5, instance.getTableSize()); - assertEquals(1, instance.getModifiedCount()); - - assertEquals(Integer.valueOf(25), instance.get(5, (key) -> key * key, 1)); - assertEquals(5, instance.getSize()); - assertEquals(5, instance.getTableSize()); - assertEquals(2, instance.getModifiedCount()); - - assertEquals(Integer.valueOf(2), instance.get(1, (key) -> key + 1, 1, System.currentTimeMillis() + 1500)); - assertEquals(5, instance.getSize()); - assertEquals(5, instance.getTableSize()); - assertEquals(2, instance.getModifiedCount()); - - assertEquals(Integer.valueOf(9), instance.get(3)); - assertEquals(Integer.valueOf(4), instance.get(2)); - instance.remove(3); - assertNull(instance.get(3)); - assertEquals(Integer.valueOf(4), instance.get(2)); - - assertEquals(4, instance.getSize()); - assertEquals(5, instance.getTableSize()); - assertEquals(3, instance.getModifiedCount()); - - assertEquals(Integer.valueOf(3), instance.get(3, (key) -> key, 2000)); - assertEquals(5, instance.getSize()); - assertEquals(5, instance.getTableSize()); - assertEquals(4, instance.getModifiedCount()); - - + //TODO } } \ No newline at end of file diff --git a/src/test/java/ua/net/uid/utils/io/FifoCacheTest.java b/src/test/java/ua/net/uid/utils/io/FifoCacheTest.java new file mode 100644 index 0000000..8f2d5b8 --- /dev/null +++ b/src/test/java/ua/net/uid/utils/io/FifoCacheTest.java @@ -0,0 +1,49 @@ +package ua.net.uid.utils.io; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * + * @author nightfall + */ +public class FifoCacheTest { + @Test + public void testGet() { + FifoCache cache = new FifoCache<>(5); + for (int i = 0; i < 5; ++i) { // new values + assertEquals(Integer.valueOf(i * i + 1), cache.get(i, (t) -> t * t + 1)); + } + for (int i = 0; i < 5; ++i) { // exists values + assertEquals(Integer.valueOf(i * i + 1), cache.get(i, (t) -> 0)); + } + assertEquals(Integer.valueOf(6 * 6), cache.get(6, (t) -> t * t)); + assertEquals(Integer.valueOf(0), cache.get(0, (t) -> 0)); + } + /* + @Test + public void testTmp() { + TimeZone zone = TimeZone.getTimeZone("Europe/Kiev"); + Calendar calendar = Calendar.getInstance(zone); + calendar.setTimeInMillis(1566223311001L); + + assertEquals(19, calendar.get(Calendar.DAY_OF_MONTH)); + assertEquals(17, calendar.get(Calendar.HOUR_OF_DAY)); + assertEquals(1, calendar.get(Calendar.MINUTE)); + assertEquals(51, calendar.get(Calendar.SECOND)); + assertEquals(1, calendar.get(Calendar.MILLISECOND)); + + calendar.set(Calendar.MILLISECOND, 0); + assertEquals(0, calendar.get(Calendar.MILLISECOND)); + assertEquals(1566223311000L, calendar.getTimeInMillis()); + + calendar.set(Calendar.SECOND, 0); + assertEquals(0, calendar.get(Calendar.SECOND)); + assertEquals(1566223260000L, calendar.getTimeInMillis()); + + calendar.set(Calendar.MINUTE, 0); + assertEquals(0, calendar.get(Calendar.MINUTE)); + assertEquals(1566223200000L, calendar.getTimeInMillis()); + } + */ +} diff --git a/src/test/java/ua/net/uid/utils/io/LocalCacheTest.java b/src/test/java/ua/net/uid/utils/io/LocalCacheTest.java index 2cfef8b..39453e9 100644 --- a/src/test/java/ua/net/uid/utils/io/LocalCacheTest.java +++ b/src/test/java/ua/net/uid/utils/io/LocalCacheTest.java @@ -7,29 +7,29 @@ import static org.junit.jupiter.api.Assertions.*; -@SuppressWarnings("unchecked") +//@SuppressWarnings("unchecked") class LocalCacheTest { @Test void testFuture_GenericType() throws InterruptedException, ExecutionException { - LocalCache instance = new LocalCache(); + LocalCache instance = new LocalCache<>(); instance.set("test", 123); - Future result = instance.future("test"); + Future result = instance.future("test"); assertNotNull(result); assertEquals(123, result.get()); } @Test void testFuture_GenericType_Callable() throws InterruptedException, ExecutionException { - LocalCache instance = new LocalCache(); - Future result = instance.future("test", () -> 456); + LocalCache instance = new LocalCache<>(); + Future result = instance.future("test", () -> 456); assertNotNull(result); assertEquals(456, result.get()); } @Test void testGet_GenericType() { - LocalCache instance = new LocalCache(); + LocalCache instance = new LocalCache<>(); instance.set("test", 789); Object result = instance.get("test"); assertNotNull(result); @@ -38,7 +38,7 @@ @Test void testGet_GenericType_Callable() { - LocalCache instance = new LocalCache(); + LocalCache instance = new LocalCache<>(); Object result = instance.get("test", () -> 65535); assertNotNull(result); assertEquals(65535, result); @@ -46,27 +46,27 @@ @Test void testSet_GenericType_GenericType() throws InterruptedException, ExecutionException { - LocalCache instance = new LocalCache(); + LocalCache instance = new LocalCache<>(); instance.set("test", 2345); - Future result = instance.future("test"); + Future result = instance.future("test"); assertNotNull(result); assertEquals(2345, result.get()); } @Test void testSet_GenericType_Callable() throws InterruptedException, ExecutionException { - LocalCache instance = new LocalCache(); + LocalCache instance = new LocalCache<>(); instance.put("testSet_GenericType_Callable", () -> "testSet_GenericType_Callable"); - Future result = instance.future("testSet_GenericType_Callable"); + Future result = instance.future("testSet_GenericType_Callable"); assertNotNull(result); assertEquals("testSet_GenericType_Callable", result.get()); } @Test void testExtractFuture() throws InterruptedException, ExecutionException { - LocalCache instance = new LocalCache(); + LocalCache instance = new LocalCache<>(); instance.put("testExtractFuture", () -> "testExtractFuture"); - Future result = instance.extractFuture("testExtractFuture"); + Future result = instance.extractFuture("testExtractFuture"); assertNotNull(result); assertNull(instance.future("testExtractFuture")); assertEquals("testExtractFuture", result.get()); @@ -74,7 +74,7 @@ @Test void testExtract() { - LocalCache instance = new LocalCache(); + LocalCache instance = new LocalCache<>(); instance.put("testExtract", () -> "testExtract"); Object result = instance.extract("testExtract"); assertNotNull(result); @@ -84,7 +84,7 @@ @Test void testRemove() { - LocalCache instance = new LocalCache(); + LocalCache instance = new LocalCache<>(); instance.put("testRemove", () -> "testRemove"); instance.remove("testExtract"); assertNull(instance.future("testExtract")); @@ -92,7 +92,7 @@ @Test void testClear() { - LocalCache instance = new LocalCache(); + LocalCache instance = new LocalCache<>(); instance.put("testClear", () -> "testClear"); instance.clear(); assertNull(instance.future("testClear")); @@ -100,7 +100,7 @@ @Test void testCount() { - LocalCache instance = new LocalCache(); + LocalCache instance = new LocalCache<>(); instance.set(0, 0); instance.set(1, 1); instance.set(2, 2); diff --git a/src/test/java/ua/net/uid/utils/io/SimpleWriterTest.java b/src/test/java/ua/net/uid/utils/io/SimpleWriterTest.java index cd3bb91..cb6d57a 100644 --- a/src/test/java/ua/net/uid/utils/io/SimpleWriterTest.java +++ b/src/test/java/ua/net/uid/utils/io/SimpleWriterTest.java @@ -11,124 +11,139 @@ @Test void testWriteChar() { - SimpleWriter instance = new SimpleWriter(); - instance.write(32); - assertEquals(" ", instance.toString()); + try (SimpleWriter instance = new SimpleWriter()) { + instance.write(32); + assertEquals(" ", instance.toString()); + } } @Test void testWriteCharsFromOffsetWithLength() { char[] buf = "aaa0123456789bbb".toCharArray(); - SimpleWriter instance = new SimpleWriter(); - instance.write(buf, 3, 10); - assertEquals("0123456789", instance.toString()); + try (SimpleWriter instance = new SimpleWriter()) { + instance.write(buf, 3, 10); + assertEquals("0123456789", instance.toString()); + } } @Test void testWriteString() { String str = "prototype"; - SimpleWriter instance = new SimpleWriter(); - instance.write(str); - assertEquals(str, instance.toString()); + try (SimpleWriter instance = new SimpleWriter()) { + instance.write(str); + assertEquals(str, instance.toString()); + } } @Test void testWriteStringFromOffsetWithLength() { String buf = "aaa0123456789bbb"; - SimpleWriter instance = new SimpleWriter(); - instance.write(buf, 3, 10); - assertEquals("0123456789", instance.toString()); + try (SimpleWriter instance = new SimpleWriter()) { + instance.write(buf, 3, 10); + assertEquals("0123456789", instance.toString()); + } } @Test void testAppendCharSequence() { - SimpleWriter instance = new SimpleWriter(); - Writer result = instance.append("test"); - assertEquals(result, instance); - assertEquals("test", result.toString()); + try (SimpleWriter instance = new SimpleWriter()) { + Writer result = instance.append("test"); + assertEquals(result, instance); + assertEquals("test", result.toString()); + } } @Test void testAppendCharSequenceFromOffsetWithLength() { CharSequence data = "aaa0123456789bbb"; - SimpleWriter instance = new SimpleWriter(); - Writer result = instance.append(data, 3, 10); - assertEquals(result, instance); - assertEquals("0123456", result.toString()); + try (SimpleWriter instance = new SimpleWriter()) { + Writer result = instance.append(data, 3, 10); + assertEquals(result, instance); + assertEquals("0123456", result.toString()); + } } @Test void testAppendChar() { - SimpleWriter instance = new SimpleWriter(); - Writer result = instance.append(' '); - assertEquals(result, instance); - assertEquals(" ", instance.toString()); + try (SimpleWriter instance = new SimpleWriter()) { + Writer result = instance.append(' '); + assertEquals(result, instance); + assertEquals(" ", instance.toString()); + } } @Test void testFlush() { - SimpleWriter instance = new SimpleWriter(); - instance.write("The test case is a prototype."); - instance.flush(); - assertEquals("The test case is a prototype.", instance.toString()); + try (SimpleWriter instance = new SimpleWriter()) { + instance.write("The test case is a prototype."); + instance.flush(); + assertEquals("The test case is a prototype.", instance.toString()); + } } @Test void testClose() { - SimpleWriter instance = new SimpleWriter(); - instance.write("The test case is a prototype."); - instance.close(); - assertEquals("The test case is a prototype.", instance.toString()); + try (SimpleWriter instance = new SimpleWriter()) { + instance.write("The test case is a prototype."); + instance.close(); + assertEquals("The test case is a prototype.", instance.toString()); + } } @Test void testLength() { String data = "aaa0123456789bbb"; - SimpleWriter instance = new SimpleWriter(); - instance.write(data); - assertEquals(data.length(), instance.length()); + try (SimpleWriter instance = new SimpleWriter()) { + instance.write(data); + assertEquals(data.length(), instance.length()); + } } @Test void testCharAt() { String data = "aaa0123456789bbb"; - SimpleWriter instance = new SimpleWriter(); - instance.write(data); - assertEquals(data.charAt(3), instance.charAt(3)); + try (SimpleWriter instance = new SimpleWriter()) { + instance.write(data); + assertEquals(data.charAt(3), instance.charAt(3)); + } } @Test void testSubSequence() { String data = "aaa0123456789bbb"; - SimpleWriter instance = new SimpleWriter(); - instance.write(data); - assertEquals("0123456", instance.subSequence(3, 10)); + try (SimpleWriter instance = new SimpleWriter()) { + instance.write(data); + assertEquals("0123456", instance.subSequence(3, 10)); + } } @Test void testToString() { String data = "aaa0123456789bbb"; - SimpleWriter instance = new SimpleWriter(); - instance.write(data); - assertEquals(data, instance.toString()); + try (SimpleWriter instance = new SimpleWriter()) { + instance.write(data); + assertEquals(data, instance.toString()); + } } @Test void testGetBuilder() { String data = "aaa0123456789bbb"; - SimpleWriter instance = new SimpleWriter(); - instance.write(data); - StringBuilder result = instance.getBuilder(); - assertEquals(data, result.toString()); + try (SimpleWriter instance = new SimpleWriter()) { + instance.write(data); + StringBuilder result = instance.getBuilder(); + assertEquals(data, result.toString()); + } } @Test void testToCharArray() { char[] data = "aaa0123456789bbb".toCharArray(); - SimpleWriter instance = new SimpleWriter(); - instance.write(data); - char[] result = instance.toCharArray(); - assertArrayEquals(data, result); + try (SimpleWriter instance = new SimpleWriter()) { + instance.write(data); + char[] result = instance.toCharArray(); + assertArrayEquals(data, result); + } } } diff --git a/src/test/java/ua/net/uid/utils/time/DailyEquationTest.java b/src/test/java/ua/net/uid/utils/time/DailyEquationTest.java new file mode 100644 index 0000000..95b1de1 --- /dev/null +++ b/src/test/java/ua/net/uid/utils/time/DailyEquationTest.java @@ -0,0 +1,106 @@ +/* + * 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.time; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.TimeZone; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + +/** + * + * @author nightfall + */ +public class DailyEquationTest { + private static final SimpleDateFormat DATE_FORMAT_DAY = new SimpleDateFormat("yyyyMMdd"); + private static final SimpleDateFormat DATE_FORMAT_MINUTES = new SimpleDateFormat("yyyyMMdd HH:mm"); + + @Test + public void testCalculateEvent() { + //https://edwilliams.org/sunrise_sunset_example.htm + assertEquals(9.441, DailyEquation.calculateEvent(40.9, -74.3 / 15, Zenith.OFFICIAL.getDegrees(), 176, true), 0.001); + } + + @Test + public void testGetSunEvents() throws ParseException { + //https://edwilliams.org/sunrise_sunset_example.htm + assertEvents("America/New_York", "19900625", 40.9, -74.3, "05:26", "20:33"); // June 25, 1990 / Wayne, NJ + + //https://github.com/caarmen/SunriseSunset/blob/master/library/src/test/java/ca/rmen/sunrisesunset/test/SunriseSunsetTest.java + assertEvents("PST", "20130120", 34.0522, -118.2437, "06:56", "17:11"); + assertEvents("CET", "20130120", 48.8567, 2.351, "08:35", "17:28"); + assertEvents("Australia/Sydney", "20121225", -33.86, 151.2111, "05:43", "20:07"); + assertEvents("Japan", "20130501", 35.6938, 139.7036, "04:50", "18:27"); + assertEvents("Europe/Dublin", "20130605", 53.3441, -6.2675, "05:00", "21:46"); + assertEvents("CST", "20130622", 41.8781, -87.6298, "05:15", "20:29"); + assertEvents("Pacific/Honolulu", "20150827", 21.3069, -157.8583, "06:13", "18:51"); + assertEvents("America/Argentina/Buenos_Aires", "20130501", -34.6092, -58.3732, "07:29", "18:11"); + assertEvents("America/Argentina/Buenos_Aires", "20131019", -34.6092, -58.3732, "06:06", "19:10"); + + assertEvents("America/Argentina/Buenos_Aires", "20130126", -34.6092, -58.3732, "06:07", "20:04"); + assertEvents("America/Argentina/Buenos_Aires", "20131020", -34.6092, -58.3732, "06:05", "19:11"); + assertEvents("America/Argentina/Buenos_Aires", "20131031", -34.6092, -58.3732, "05:53", "19:21"); + + assertEvents("Antarctica/McMurdo", "20150419", -77.8456, 166.6693, "10:34", "15:04"); // "10:37", "15:08" + assertEvents("Antarctica/McMurdo", "20150621", -77.8456, 166.6693, Zenith.OFFICIAL, DailyEventType.POLAR_NIGHT, null, null); + assertEvents("Antarctica/McMurdo", "20150921", -77.8456, 166.6693, "06:49", "18:47"); + assertEvents("Antarctica/McMurdo", "20151221", -77.8456, 166.6693, Zenith.OFFICIAL, DailyEventType.POLAR_DAY, null, null); + + //https://github.com/caarmen/SunriseSunset/blob/master/library/src/test/java/ca/rmen/sunrisesunset/test/SunriseSunsetSpecificLocationsTest.java + assertEvents("EST", "20160228", 82.50178, -62.34809, "10:13", "12:47"); // "10:27", "12:19 + assertEvents("EST", "20160228", 82.5018, -62.3481, "10:13", "12:47"); // "10:27", "12:19" + assertEvents("EST", "20160228", 82.50177764892578, -62.34809112548828, "10:13", "12:47"); // "10:17", "12:31" + assertEvents("EST", "20160228", 82.501667, -62.348056, "10:13", "12:47"); // "10:15", "12:32" + assertEvents("EST", "20160228", 82.5, -62.35, "10:13", "12:48"); // "10:14", "12:33" + assertEvents("EST", "20160228", 82.50177764892578, -62.34809112548828, "10:13", "12:47"); // "10:14", "12:33" + + assertEvents("Europe/Kiev", "20190708", 50.401984, 30.531065, "04:55", "21:09" ); + assertEvents("Asia/Kamchatka", "20190706", 53.047252, 158.628714, "05:07", "21:52"); + + assertEvents("America/Moscow", "20181201", 69.000779, 33.116392, "09:14", "09:44"); // Мурманск - https://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D0%BB%D1%8F%D1%80%D0%BD%D0%B0%D1%8F_%D0%BD%D0%BE%D1%87%D1%8C + assertEvents("America/Moscow", "20181202", 69.000779, 33.116392, Zenith.OFFICIAL, DailyEventType.POLAR_NIGHT, null, null); + assertEvents("America/Moscow", "20190111", 69.000779, 33.116392, Zenith.OFFICIAL, DailyEventType.POLAR_NIGHT, null, null); + assertEvents("America/Moscow", "20190112", 69.000779, 33.116392, "09:29", "10:29"); + + assertEvents("Atlantic/Reykjavik", "20190708", 65.67, -18.1, "02:26", "00:06"); // Акюрейри, Регион Нордюрланд-Эйстра, Исландия + + } + + private void assertEvents(String timezone, String date, double lat, double lon, String sr, String ss) throws ParseException { + assertEvents(timezone, date, lat, lon, Zenith.OFFICIAL, DailyEventType.NORMAL_DAY, sr, ss); + } + private void assertEvents(String timezone, String date, double lat, double lon, Zenith zenith, DailyEventType type, String sr, String ss) throws ParseException { + TimeZone tz = TimeZone.getTimeZone(timezone); + + SimpleDateFormat parse = (SimpleDateFormat) DATE_FORMAT_DAY.clone(); + parse.setTimeZone(tz); + + Calendar calendar = Calendar.getInstance(tz); + calendar.setTime(parse.parse(date)); + + DailyEvents events = DailyEquation.getSunEvents(lat, lon, calendar, zenith); + + assertSame(type, events.getType()); + if (type == DailyEventType.NORMAL_DAY) { + SimpleDateFormat format = (SimpleDateFormat) DATE_FORMAT_MINUTES.clone(); + format.setTimeZone(tz); + assertEquals(date + ' ' + sr, format.format(events.getSunrise())); + assertEquals(date + ' ' + ss, format.format(events.getSunset())); + } + } +} diff --git a/src/test/java/ua/net/uid/utils/tools/DailyEquationTest.java b/src/test/java/ua/net/uid/utils/tools/DailyEquationTest.java index 05920f9..3c27827 100644 --- a/src/test/java/ua/net/uid/utils/tools/DailyEquationTest.java +++ b/src/test/java/ua/net/uid/utils/tools/DailyEquationTest.java @@ -1,92 +1 @@ package ua.net.uid.utils.tools; - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.TimeZone; -import static org.junit.jupiter.api.Assertions.*; -import org.junit.jupiter.api.Test; -import static ua.net.uid.utils.tools.DailyEquation.*; - -/** - * - * @author nightfall - */ -public class DailyEquationTest { - private static final SimpleDateFormat DATE_FORMAT_DAY = new SimpleDateFormat("yyyyMMdd"); - private static final SimpleDateFormat DATE_FORMAT_MINUTES = new SimpleDateFormat("yyyyMMdd HH:mm"); - - @Test - public void testCalculateEvent() { - //https://edwilliams.org/sunrise_sunset_example.htm - assertEquals(9.441, DailyEquation.calculateEvent(40.9, -74.3 / 15, Zenith.OFFICIAL.getDegrees(), 176, true), 0.001); - } - - @Test - public void testGetSunEvents() throws ParseException { - //https://edwilliams.org/sunrise_sunset_example.htm - assertEvents("America/New_York", "19900625", 40.9, -74.3, "05:26", "20:33"); // June 25, 1990 / Wayne, NJ - - //https://github.com/caarmen/SunriseSunset/blob/master/library/src/test/java/ca/rmen/sunrisesunset/test/SunriseSunsetTest.java - assertEvents("PST", "20130120", 34.0522, -118.2437, "06:56", "17:11"); - assertEvents("CET", "20130120", 48.8567, 2.351, "08:35", "17:28"); - assertEvents("Australia/Sydney", "20121225", -33.86, 151.2111, "05:43", "20:07"); - assertEvents("Japan", "20130501", 35.6938, 139.7036, "04:50", "18:27"); - assertEvents("Europe/Dublin", "20130605", 53.3441, -6.2675, "05:00", "21:46"); - assertEvents("CST", "20130622", 41.8781, -87.6298, "05:15", "20:29"); - assertEvents("Pacific/Honolulu", "20150827", 21.3069, -157.8583, "06:13", "18:51"); - assertEvents("America/Argentina/Buenos_Aires", "20130501", -34.6092, -58.3732, "07:29", "18:11"); - assertEvents("America/Argentina/Buenos_Aires", "20131019", -34.6092, -58.3732, "06:06", "19:10"); - - assertEvents("America/Argentina/Buenos_Aires", "20130126", -34.6092, -58.3732, "06:07", "20:04"); - assertEvents("America/Argentina/Buenos_Aires", "20131020", -34.6092, -58.3732, "06:05", "19:11"); - assertEvents("America/Argentina/Buenos_Aires", "20131031", -34.6092, -58.3732, "05:53", "19:21"); - - assertEvents("Antarctica/McMurdo", "20150419", -77.8456, 166.6693, "10:34", "15:04"); // "10:37", "15:08" - assertEvents("Antarctica/McMurdo", "20150621", -77.8456, 166.6693, Zenith.OFFICIAL, Type.POLAR_NIGHT, null, null); - assertEvents("Antarctica/McMurdo", "20150921", -77.8456, 166.6693, "06:49", "18:47"); - assertEvents("Antarctica/McMurdo", "20151221", -77.8456, 166.6693, Zenith.OFFICIAL, Type.POLAR_DAY, null, null); - - //https://github.com/caarmen/SunriseSunset/blob/master/library/src/test/java/ca/rmen/sunrisesunset/test/SunriseSunsetSpecificLocationsTest.java - assertEvents("EST", "20160228", 82.50178, -62.34809, "10:13", "12:47"); // "10:27", "12:19 - assertEvents("EST", "20160228", 82.5018, -62.3481, "10:13", "12:47"); // "10:27", "12:19" - assertEvents("EST", "20160228", 82.50177764892578, -62.34809112548828, "10:13", "12:47"); // "10:17", "12:31" - assertEvents("EST", "20160228", 82.501667, -62.348056, "10:13", "12:47"); // "10:15", "12:32" - assertEvents("EST", "20160228", 82.5, -62.35, "10:13", "12:48"); // "10:14", "12:33" - assertEvents("EST", "20160228", 82.50177764892578, -62.34809112548828, "10:13", "12:47"); // "10:14", "12:33" - - assertEvents("Europe/Kiev", "20190708", 50.401984, 30.531065, "04:55", "21:09" ); - assertEvents("Asia/Kamchatka", "20190706", 53.047252, 158.628714, "05:07", "21:52"); - - assertEvents("America/Moscow", "20181201", 69.000779, 33.116392, "09:14", "09:44"); // Мурманск - https://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D0%BB%D1%8F%D1%80%D0%BD%D0%B0%D1%8F_%D0%BD%D0%BE%D1%87%D1%8C - assertEvents("America/Moscow", "20181202", 69.000779, 33.116392, Zenith.OFFICIAL, Type.POLAR_NIGHT, null, null); - assertEvents("America/Moscow", "20190111", 69.000779, 33.116392, Zenith.OFFICIAL, Type.POLAR_NIGHT, null, null); - assertEvents("America/Moscow", "20190112", 69.000779, 33.116392, "09:29", "10:29"); - - assertEvents("Atlantic/Reykjavik", "20190708", 65.67, -18.1, "02:26", "00:06"); // Акюрейри, Регион Нордюрланд-Эйстра, Исландия - - } - - private void assertEvents(String timezone, String date, double lat, double lon, String sr, String ss) throws ParseException { - assertEvents(timezone, date, lat, lon, Zenith.OFFICIAL, Type.NORMAL_DAY, sr, ss); - } - private void assertEvents(String timezone, String date, double lat, double lon, Zenith zenith, Type type, String sr, String ss) throws ParseException { - TimeZone tz = TimeZone.getTimeZone(timezone); - - SimpleDateFormat parse = (SimpleDateFormat) DATE_FORMAT_DAY.clone(); - parse.setTimeZone(tz); - - Calendar calendar = Calendar.getInstance(tz); - calendar.setTime(parse.parse(date)); - - Events events = DailyEquation.getSunEvents(lat, lon, calendar, zenith); - - assertSame(type, events.getType()); - if (type == Type.NORMAL_DAY) { - SimpleDateFormat format = (SimpleDateFormat) DATE_FORMAT_MINUTES.clone(); - format.setTimeZone(tz); - assertEquals(date + ' ' + sr, format.format(events.getSunrise())); - assertEquals(date + ' ' + ss, format.format(events.getSunset())); - } - } -}