PHPackages                             warrickbayman/loom - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. warrickbayman/loom

Abandoned → [nesbot/carbon](/?search=nesbot%2Fcarbon)ArchivedLibrary[Utility &amp; Helpers](/categories/utility)

warrickbayman/loom
==================

A simple way to work with units of time.

1.0.2(10y ago)12.1k[1 PRs](https://github.com/warrickbayman/Loom/pulls)MITPHPPHP &gt;=5.4.0

Since Jan 20Pushed 9y ago1 watchersCompare

[ Source](https://github.com/warrickbayman/Loom)[ Packagist](https://packagist.org/packages/warrickbayman/loom)[ RSS](/packages/warrickbayman-loom/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (5)Dependencies (1)Versions (8)Used By (0)

Loom
====

[](#loom)

[![Build Status](https://camo.githubusercontent.com/609e8a39f7dab296386d08b5ad8cafcdfbd3cc2c8298e5fbdab72fe0c6988525/68747470733a2f2f7472617669732d63692e6f72672f7761727269636b6261796d616e2f4c6f6f6d2e7376673f6272616e63683d312e31)](https://travis-ci.org/warrickbayman/Loom)[![Stable](https://camo.githubusercontent.com/d3ec3a42f9039867a949c0471b110f0db1e4e38003c809009cad18c06187001f/68747470733a2f2f706f7365722e707567782e6f72672f7761727269636b6261796d616e2f6c6f6f6d2f762f737461626c652e737667)](https://packagist.org/packages/warrickbayman/loom)[![Latest Unstable Version](https://camo.githubusercontent.com/a257fde215debdc4adb5415b4c80a84abd22879b63de08c31b44728bc7736d75/68747470733a2f2f706f7365722e707567782e6f72672f7761727269636b6261796d616e2f6c6f6f6d2f762f756e737461626c65)](https://packagist.org/packages/warrickbayman/loom)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/cec9ec9cad7320affc487d867a22ebfd2ee723ad9a12294595be5eafff603fb6/68747470733a2f2f696d672e736869656c64732e696f2f7363727574696e697a65722f672f7761727269636b6261796d616e2f4c6f6f6d2e7376673f6272616e63683d312e31)](https://scrutinizer-ci.com/g/warrickbayman/Loom/?branch=1.1)[![License](https://camo.githubusercontent.com/6f8b37eec46b73c8b25b74fede70e23b4f89c7d22f2fa01d3585148e8ea4fcdf/68747470733a2f2f706f7365722e707567782e6f72672f7761727269636b6261796d616e2f6c6f6f6d2f6c6963656e7365)](https://packagist.org/packages/warrickbayman/loom)

[![SensioLabsInsight](https://camo.githubusercontent.com/781954d8929c81585bcbd78166814b7d2990e88b3713d41eef38fc9a43d46c1f/68747470733a2f2f696e73696768742e73656e73696f6c6162732e636f6d2f70726f6a656374732f37376531363136642d623232302d343033312d396137342d3435646265393235386431642f736d616c6c2e706e67)](https://insight.sensiolabs.com/projects/77e1616d-b220-4031-9a74-45dbe9258d1d)

Loom is a super simple way to work with units of time (hours, minutes, seconds, etc).

Why?
----

[](#why)

Because who knows what this means?

```
$something = someFunctionWithTime(7200);
```

The `7200` is meaningless. Seconds? Hours? Years? So I started Loom to wrap numbers when working with time constants in a way that was readable:

```
$loom = Loom::make()->fromHours(2);
$something = someFunctionWithTime($loom->getSeconds());
```

Sure, it's longer, but it's so much easier to read. Plus, you get a bit of functionality to convert from one unit of time to another.

Loom is tested on PHP 5.4, 5.5, 5.6, 7.0 and HHVM. It has no dependencies except for PHPUnit when testing. It is framework agnostic, but I use it quite a bit on a number of projects mostly using the Laravel framework, so it's well tested there.

Let me know if and how you use it.

Installation
------------

[](#installation)

Install Loom via Composer, by adding to the `requires` section of your `composer.json` file.

```
{
	"require": {
		"warrickbayman/loom": "~1.0"
	}
}
```

Run `composer update` in your project root to install Loom.

Use
---

[](#use)

### Creating a new Loom object

[](#creating-a-new-loom-object)

There are three methods to choose from when instantiating Loom.

You create a new instance of the `Loom` object:

```
$loom = new Loom\Loom(new Loom\Seconds(100));
```

To avoid having to use the `Loom` namespace each time, you could add it to your `use` clause:

```
use Loom\Loom;
use Loom\Seconds;

class MyLoomClass
{
	public function translate()
	{
		$loom = new Loom(new Seconds(100));
	}
}
```

A recommended method is to inject the `LoomFactory` class into your constructor and call the available creation methods from there:

```
class MyLoomClass
{
	private $loom;

	public function __construct(Loom\LoomFactory $loom)
	{
		$this->loom = $loom->fromSeconds(240);
	}

	public function translate()
	{
		return $this->loom->getMinutes();        // 4
	}
}
```

Lastly, the simplest by far, is to call the static `make()` method on the `Loom` object, which returns a new instance of `LoomFactory`. Since the creation methods on `LoomFactory` returns a new `Loom` object, you can chain the translator methods onto the factory creation, and use Loom in a single line:

```
$minutes = Loom::make()->fromHours(2)->getMinutes();    // 120
```

The creation methods on `LoomFactory`:

```
$loomFactory->fromMicroseconds($microseconds);
$loomFactory->fromMilliseconds($milliseconds);
$loomFactory->fromSeconds($seconds);
$loomFactory->fromMinutes($minutes);
$loomFactory->fromHours($hours);
$loomFactory->fromDays($days);
$loomFactory->fromWeeks($weeks);
$loomFactory->fromMonths($months);
$loomFactory->fromYears($years);
```

There is also a `fromLoom()` method which creates a new instance of the `Loom` object passed as a paramter.

**Note:** that the `fromLoom()` used to be named `copy()` but was never documented. Just in case, I've deprecated the `copy()` method until the next major release.

### Using DateTime

[](#using-datetime)

The `LoomFactory` object also provides a `fromDateTime` method which allows you to create a Loom object from a `DateTime` object.

```
$loom = $loomFactory->fromDateTime(new \DateTime('2015-01-21');
```

The new loom object will represent the amount of time that has passed since the Epoc (1970-01-01 00:00:00). So, in other words, doing this...

```
var_dump($loom->getHours());
```

... will get you the number of hours since the 1st of January 1970. This becomes a little more useful when you you need to get the difference between two specific dates:

```
$loom = Loom::make()->fromDateTime(new \DateTime('2015-01-21'));
$result = $loom->diff(Loom::make()->fromDateTime(new \DateTime('2015-01-27'));

var_dump($result->getDays());     // 6
var_dump($result->getHours());    // 144
var_dump($result->getMinutes());  // 8640
```

And since libraries like `nesbot\carbon` simply extend the `DateTime` object, you can do things like this as well...

```
$loom = Loom::make()->fromTime(\Carbon\Carbon::now());
```

### Getters

[](#getters)

Loom provides some simple ways to translate from one unit to another.

```
$microseconds = $loom->getMicroseconds();
$milliseconds = $loom->getMilliseconds();
$seconds = $loom->getSeconds();
$minutes = $loom->getMinutes();
$hours = $loom->getHours();
$days = $loom->getDays();
$weeks = $loom->getWeeks();
$months = $loom->getMonths();
$years = $loom->getYears();
```

Each of the getters return a float.

### Days per month get averaged!

[](#days-per-month-get-averaged)

By default, Loom will average the number of days per month. This means results can be unexpected when working with months:

```
$loom = Loom::make()->fromDays(30);
var_dump($loom->getMonths());		// Returns 0.98630136986301

$loom = Loom::make()->fromMonths(1);
var_dump($loom->getDays());			// Returns 30.416666666667
```

To prevent this from happening, the `getMonths()` method will accept an integer for the number of days in a month, so you could do:

```
$loom = Loom::make()->fromDays(60);
var_dump($loom->getMonths(30));     // 2
```

You can do the same when creating a new `Loom` object from Months:

```
$loom = Loom::make()->fromMonths(12, 31);
var_dump($loom->getDays());		// 372
```

### Solar Year

[](#solar-year)

A year is not exactly 365 days long. Instead, it is ever so slightly longer than that. The current mean solar year is 365 days, 5 hours, 48 minutes and 45.19 seconds. Loom can use the solar year length of 365.2421897 days instead of simply 365 days by passing a boolean `true` as the second parameter when using the year methods. By default, Loom uses a flat 365 days to represent a year:

```
$loom = Loom::make()->fromYears(1, true);
var_dump($loom->getDays());		// 365.2421897

$loom = Loom:make()->fromMonths(12);
var_dump($loom->getYears(true));	// 0.99933690656
```

### Difference

[](#difference)

You can use the `diff()` method to get the difference between two Loom objects. The `diff()` method returns a new Loom object.

```
$loom1 = Loom::make()->fromDays(1);
$loom2 = Loom::make()->fromHours(48);

$diff = $loom1->diff($loom2);

var_dump($diff->getHours());		// Returns 24.
```

It doesn't matter which object you call the `diff()` method on. The result will be the same either way.

There are also two time saving methods available which returns the difference until a specific time, or since a specific time. The aptly name `until()` and `since()` methods are only really useful if you first create a Loom object from a PHP `DateTime` object. Both methods return a new Loom object.

```
$loomPast = Loom::make()->fromDateTime(new \DateTime('now - 5 days'));
$loomFuture = Loom::make()->fromDateTime(new \DateTime('now + 10 days'));

var_dump($loomPast->since()->getHours());       // Returns 120.
var_dump($loomFuture->until()->getHours());     // Returns 240.
```

The `since()` and `until()` methods simply do a `diff()` on the two Loom objects, and since the `diff()` method will always return a positive number, the `since()` and `until()` methods are actually identical. They exist simply to help make your code a little more readable.

### Comparisons

[](#comparisons)

A number of comparison methods also exist:

```
$loom1 = Loom::make()->fromDays(1);
$loom2 = Loom::make()->fromHours(48);

// Equal to
$loom1->eq($loom2);			// false

// Not equal to
$loom1->neq($loom2);		// true

// Greater than
$loom1->gt($loom2);			// false

// Greater than or equal to
$loom1->gte($loom2);		// false

// Less than
$loom1->lt($loom2);			// true

// Less than or equal to
$loom1->lte($loom2);		// true
```

Here it *is* important which object you call the comparison methods on. The object you call on is always on the left of the equasion.

### Between

[](#between)

Loom provides a way to check if a unit falls between two other units. The `isBetween` method takes two Loom objects which means you can use any of the creation methods:

```
$loom = Loom::make()->fromSeconds(100);
if ($loom->isBetween(
	Loom::make()->fromMinutes(1),
	Loom::make()->fromMinutes(2)
)) {
	echo 'Hooray!';
}
```

The `isBetween` method is also accepts a second boolean parameter to specify if the the limits should be inclusive or exclusive. By default, `isBetween` is exclusive of the limits. In otherwords, if the value you are checking is equal to the upper limit, the result will be `false`.

You can get `isBetween` to include the limits in the comparrison by passing a boolean `true` as the third parameter:

```
$loom = Loom::make()->fromSeconds(120);

// Default is exclusive. Returns false.
var_dump($loom->isBetween(
	Loom::make()->fromMinutes(1),
	Loom::make()->fromMinutes(2)
));

// Inclusive. Returns true.
var_dump($loom->isBetween(
	Loom::make()->fromMinutes(1),
	Loom::make()->fromMinutes(2),
	true
));
```

### Simple Arithmetic

[](#simple-arithmetic)

You can perform some simple arithmetic through the `add()` and `sub()` methods:

```
	$loom = Loom::make()->fromMinutes(2);
	$loom->add(Loom::make()->fromSeconds(30));
	var_dump($loom->getSeconds())			// 150

	$loom->sub(Loom::make()->fromHours(1));
	var_dump($loom->getMilliseconds);		// 0
```

A `Loom` object can never have a negative value. Subtracting a larger Loom from a smaller one will always result in 0.

The arithmetic methods will accept an instance of `AbstractUnit`, so you don't need to create another `Loom` object. You can just pass the unit into the methods:

```
	$loom = Loom::make()->fromMinutes(2);
	$loom->add(new Loom\Seconds(60));
	var_dump($loom->getSeconds());		// 180

	$loom->sub(new Loom\Minutes(2));
	var_dump($loom->getSeconds());		// 60
```

Loom Collections
----------------

[](#loom-collections)

A new `LoomCollection` class is currently in development and is available on the `develop` branch. Loom Collections are based on the Laravel `Collection` class, but with some *Loomness* built in.

The new `LoomCollection` class constructor accepts an array of Loom objects, but you can also create an empty collection:

```
$collection = new Loom\LoomCollection();
```

Loom Collections can only contain `Loom` objects. You'll get an exception if you try add anything else.

### Push, Pop, Prepend, Shift

[](#push-pop-prepend-shift)

Manipulating the contents of a `LoomCollection` is quite simple. Use the `push` method to push a new Loom object onto the end of the collection, the `pop` method to pull the last Loom object, the `prepend` method to insert a Loom object onto the beginning of the collection and `shift` to pull the first objct.

```
// Add to the end of the collection
$collection->push(new Loom::make()->fromMinutes(4));
// Add to the beginning of the collection
$collection->prepend(new Loom::make()->fromMinutes(10));

// Pull the last object from the collection
$loom = $collection->pop();
// Pull the first object from the collection
$loom = $collection->shift();
```

### Finding

[](#finding)

Loom provides a simple way to grab single Loom objects from the collection. You can always get the first Loom object by using the `first()` method. In the same manner, the `last()` method will always return the last object in the collection.

```
$first = $collection->first();
$last = $collection->last();
```

Unlike `pop()` and `shift()`, these methods do not alter the collection and only return the Loom object.

Sometimes, you might need to get the shortest, or longest Loom object. You can use the `shortest()` and `longest()` methods to do just that. There is also an `earliest()` method, which is just an alias for `shortest`, and a `latest()`, which is an alias for `longest`.

```
$shortest = $collection->shortest();
$longest = $collection->longest();
```

### Filtering

[](#filtering)

No collections class would be complete without the ability to filter the contents of a collection. The best place to start is the `filter` method which accepts a closure. The Loom objects are passed as parameters to the closure. If the closure returns a boolean `true` then that object is included in the filtered results:

```
$filtered = $collection->filter(function(Loom $loom)
{
    return $loom->gt(Loom::make()->fromMinutes(6);
});
```

However, Loom also includes a few extra filter methods that make this process easier. The `after()` method will return all the Loom objects that occure after the specified Loom, and the `before()` method will return lla the objects that occure before the specified Loom.

```
// After
$newCollection = $collection->after(Loom::make()->fromMinutes(8));

// Before
$newCollection = $collection->before(Loom::make()->fromMinutes(6));
```

There is also a `between()` method that will return objects that occure between the specified start and end Looms.

```
$newCollection = $collection->between(
    Loom::make()->fromMinutes(5),
    Loom::make()->fromHours(1)
);
```

### Iterating

[](#iterating)

The `LoomCollection` class also includes an `each()` method which accepts a closure to which is passed each Loom in the collection.

```
$newCollection = $collection->each(function(Loom $loom)
{
    echo $loom->getMinutes();
});
```

### Sorting

[](#sorting)

The collection can also be sorted using the appropriately named `sort()` method. By default `sort()` will sort the collection ascending (smallest Loom first), but you can invert the sort by passing a boolean `true` as parameter.

```
// Ascending
$sorted = $collection->sort();

// Descending
$sorted = $collection->sort(true);
```

Ranges
------

[](#ranges)

Loom provides an interesting feature which allows you to create a range of Loom objects. Ranges are always returned as Loom Collections. Creating a range is fairly simple. Instead of calling the `make()` static method, there is now a `makeRange()` static method on the `Loom` class. You can pass a single Loom object to the `from()` method, and one to the `to()` method. The `steps()` method takes an integer parameter and returns a new `LoomCollection` instance:

```
$range = Loom::makeRange()
    ->from(Loom::make()->fromSeconds(1))
    ->to(Loom::make()->fromSeconds(10))
    ->steps(10);
```

This will return a new `LoomCollection` consisting of 10 Loom objects. The first one being 1 seconds, and the last one being 10 seconds.

###  Health Score

30

—

LowBetter than 64% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity17

Limited adoption so far

Community4

Small or concentrated contributor base

Maturity63

Established project with proven stability

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~70 days

Recently: every ~52 days

Total

6

Last Release

3777d ago

Major Versions

0.2.3 → 1.02015-11-12

### Community

Maintainers

![](https://www.gravatar.com/avatar/89ea2dc12cd0a934de60705f8cfe47397095d842121b7d5f545dc9d1cee554ec?d=identicon)[warrickbayman](/maintainers/warrickbayman)

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/warrickbayman-loom/health.svg)

```
[![Health](https://phpackages.com/badges/warrickbayman-loom/health.svg)](https://phpackages.com/packages/warrickbayman-loom)
```

###  Alternatives

[kornrunner/secp256k1

Pure PHP secp256k1

37566.4k109](/packages/kornrunner-secp256k1)[liborm85/composer-vendor-cleaner

Composer Vendor Cleaner removes unnecessary development files and directories from vendor directory.

35342.7k1](/packages/liborm85-composer-vendor-cleaner)[makinacorpus/php-bloom

Bloom filter implementation

178.9k](/packages/makinacorpus-php-bloom)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
